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