use copysign for abs jet
abs() implementation does not correctly handle the sign of the
infinitesimal part when the value is a NaN. Define the function in terms
of copysign which is the only portable way of manipulating the sign of
a NaN value.
Change-Id: I2f13fb1db62d35ca8b09e6bff1c05a736cb91513
diff --git a/include/ceres/jet.h b/include/ceres/jet.h
index ac07b0a..be24617 100644
--- a/include/ceres/jet.h
+++ b/include/ceres/jet.h
@@ -386,6 +386,7 @@
using std::atan2;
using std::cbrt;
using std::ceil;
+using std::copysign;
using std::cos;
using std::cosh;
using std::erf;
@@ -419,10 +420,10 @@
// In general, f(a + h) ~= f(a) + f'(a) h, via the chain rule.
-// abs(x + h) ~= x + h or -(x + h)
+// abs(x + h) ~= abs(x) + sgn(x)h
template <typename T, int N>
inline Jet<T, N> abs(const Jet<T, N>& f) {
- return (f.a < T(0.0) ? -f : f);
+ return Jet<T, N>(abs(f.a), copysign(T(1), f.a) * f.v);
}
// log(a + h) ~= log(a) + h / a
diff --git a/internal/ceres/jet_test.cc b/internal/ceres/jet_test.cc
index 6e98b86..c6d2036 100644
--- a/internal/ceres/jet_test.cc
+++ b/internal/ceres/jet_test.cc
@@ -482,6 +482,12 @@
{ // Check that abs(-x * x) == sqrt(x * x).
ExpectJetsClose(abs(-x), sqrt(x * x));
}
+ {
+ J a = MakeJet(-std::numeric_limits<double>::quiet_NaN(), 2.0, 4.0);
+ J b = abs(a);
+ EXPECT_TRUE(std::signbit(b.v[0]));
+ EXPECT_TRUE(std::signbit(b.v[1]));
+ }
{ // Check that cos(acos(x)) == x.
J a = MakeJet(0.1, -2.7, 1e-3);