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);