Add erf and erfc to jet.h, including tests in jet_test.cc
erf is necessary for evaluating Gaussian functions.
erfc was added because it is so similar to erf.
Change-Id: I5e470dbe013cc938fabb87cde3b0ebf26a90fff4
diff --git a/include/ceres/jet.h b/include/ceres/jet.h
index 7aafaa0..c551d51 100644
--- a/include/ceres/jet.h
+++ b/include/ceres/jet.h
@@ -388,6 +388,8 @@
using std::ceil;
using std::cos;
using std::cosh;
+using std::erf;
+using std::erfc;
using std::exp;
using std::exp2;
using std::floor;
@@ -573,6 +575,21 @@
return y < x ? y : x;
}
+// erf is defined as an integral that cannot be expressed analyticaly
+// however, the derivative is trivial to compute
+// erf(x + h) = erf(x) + h * 2*exp(-x^2)/sqrt(pi)
+template <typename T, int N>
+inline Jet<T, N> erf(const Jet<T, N>& x) {
+ return Jet<T, N>(erf(x.a), x.v * M_2_SQRTPI * exp(-x.a*x.a));
+}
+
+// erfc(x) = 1-erf(x)
+// erfc(x + h) = erfc(x) + h * (-2*exp(-x^2)/sqrt(pi))
+template <typename T, int N>
+inline Jet<T, N> erfc(const Jet<T, N>& x) {
+ return Jet<T, N>(erfc(x.a), -x.v * M_2_SQRTPI * exp(-x.a*x.a));
+}
+
// Bessel functions of the first kind with integer order equal to 0, 1, n.
//
// Microsoft has deprecated the j[0,1,n]() POSIX Bessel functions in favour of
diff --git a/internal/ceres/jet_test.cc b/internal/ceres/jet_test.cc
index a6cad62..f1e9586 100644
--- a/internal/ceres/jet_test.cc
+++ b/internal/ceres/jet_test.cc
@@ -571,6 +571,28 @@
EXPECT_EQ(expected, b);
}
+ { // Check that erf works.
+ J a = MakeJet(10.123, -2.7, 1e-3);
+ J b = erf(a);
+ J expected = MakeJet(erf(a.a), 0.0, 0.0);
+ EXPECT_EQ(expected, b);
+ }
+ NumericalTest("erf", erf<double, 2>, -1.0);
+ NumericalTest("erf", erf<double, 2>, 1e-5);
+ NumericalTest("erf", erf<double, 2>, 0.5);
+ NumericalTest("erf", erf<double, 2>, 100.0);
+
+ { // Check that erfc works.
+ J a = MakeJet(10.123, -2.7, 1e-3);
+ J b = erfc(a);
+ J expected = MakeJet(erfc(a.a), 0.0, 0.0);
+ EXPECT_EQ(expected, b);
+ }
+ NumericalTest("erfc", erfc<double, 2>, -1.0);
+ NumericalTest("erfc", erfc<double, 2>, 1e-5);
+ NumericalTest("erfc", erfc<double, 2>, 0.5);
+ NumericalTest("erfc", erfc<double, 2>, 100.0);
+
{ // Check that cbrt(x * x * x) == x.
J z = x * x * x;
J w = cbrt(z);