Add a portable floating point classification API
Ceres has traditionally battled with portability issues
when trying to classify floating point values as one
type or another. For example, in C99 'isnan' is a
macro. Since it is a macro, it is impossible to
override the name in other namespaces.
Instead of trying to use preprocessor hacks to work
around the issue, define our own set of camel-case
names for use internally and by Ceres clients. For
example do this:
template<typename T>
void MyFunction(T x, T y) {
if (ceres::IsNaN(x)) {
...
}
}
instead of using "isnan" or "std::isnan". Note that
while GCC and Apple GCC both import 'isnan' into
the std namespace, it is not standard until C++11
which Ceres will not require for some years.
Change-Id: Ibcc96a8bb4ba63aa67cbbc58658b2e5671cd5824
diff --git a/include/ceres/fpclassify.h b/include/ceres/fpclassify.h
new file mode 100644
index 0000000..59424bf
--- /dev/null
+++ b/include/ceres/fpclassify.h
@@ -0,0 +1,49 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// Portable floating point classification. The names are picked such that they
+// do not collide with macros. For example, "isnan" in C99 is a macro and hence
+// does not respect namespaces.
+//
+// TODO(keir): Finish porting!
+
+#ifndef CERES_PUBLIC_FPCLASSIFY_H_
+#define CERES_PUBLIC_FPCLASSIFY_H_
+
+namespace ceres {
+
+inline bool IsFinite (double x) { return std::isfinite(x); }
+inline bool IsInfinite(double x) { return std::isinf(x); }
+inline bool IsNaN (double x) { return std::isnan(x); }
+inline bool IsNormal (double x) { return std::isnormal(x); }
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_FPCLASSIFY_H_
diff --git a/include/ceres/jet.h b/include/ceres/jet.h
index 50b5555..f9997bd 100644
--- a/include/ceres/jet.h
+++ b/include/ceres/jet.h
@@ -162,6 +162,7 @@
#include <string>
#include "Eigen/Core"
+#include "ceres/fpclassify.h"
namespace ceres {
@@ -401,10 +402,6 @@
inline double acos (double x) { return std::acos(x); }
inline double sin (double x) { return std::sin(x); }
inline double asin (double x) { return std::asin(x); }
-inline bool isfinite(double x) { return std::isfinite(x); }
-inline bool isinf (double x) { return std::isinf(x); }
-inline bool isnan (double x) { return std::isnan(x); }
-inline bool isnormal(double x) { return std::isnormal(x); }
inline double pow (double x, double y) { return std::pow(x, y); }
inline double atan2(double y, double x) { return std::atan2(y, x); }
@@ -482,22 +479,23 @@
}
// Jet Classification. It is not clear what the appropriate semantics are for
-// these classifications. This picks that isfinite and isnormal are "all"
-// operations, i.e. all elements of the jet must be finite for the jet itself to
-// be finite (or normal). For isnan and isinf, the answer is less clear. This
-// takes a "any" approach for isnan and isinf such that if any part of a jet is
-// nan or inf, then the entire jet is nan or inf. This leads to strange
-// situations like a jet can be both isinf and isnan, but in practice the "any"
-// semantics are the most useful for e.g. checking that derivatives are sane.
+// these classifications. This picks that IsFinite and isnormal are "all"
+// operations, i.e. all elements of the jet must be finite for the jet itself
+// to be finite (or normal). For IsNaN and IsInfinite, the answer is less
+// clear. This takes a "any" approach for IsNaN and IsInfinite such that if any
+// part of a jet is nan or inf, then the entire jet is nan or inf. This leads
+// to strange situations like a jet can be both IsInfinite and IsNaN, but in
+// practice the "any" semantics are the most useful for e.g. checking that
+// derivatives are sane.
// The jet is finite if all parts of the jet are finite.
template <typename T, int N> inline
-bool isfinite(const Jet<T, N>& f) {
- if (!isfinite(f.a)) {
+bool IsFinite(const Jet<T, N>& f) {
+ if (!IsFinite(f.a)) {
return false;
}
for (int i = 0; i < N; ++i) {
- if (!isfinite(f.v[i])) {
+ if (!IsFinite(f.v[i])) {
return false;
}
}
@@ -506,12 +504,12 @@
// The jet is infinite if any part of the jet is infinite.
template <typename T, int N> inline
-bool isinf(const Jet<T, N>& f) {
- if (isinf(f.a)) {
+bool IsInfinite(const Jet<T, N>& f) {
+ if (IsInfinite(f.a)) {
return true;
}
for (int i = 0; i < N; i++) {
- if (isinf(f.v[i])) {
+ if (IsFinite(f.v[i])) {
return true;
}
}
@@ -520,12 +518,12 @@
// The jet is NaN if any part of the jet is NaN.
template <typename T, int N> inline
-bool isnan(const Jet<T, N>& f) {
- if (isnan(f.a)) {
+bool IsNaN(const Jet<T, N>& f) {
+ if (IsNaN(f.a)) {
return true;
}
for (int i = 0; i < N; ++i) {
- if (isnan(f.v[i])) {
+ if (IsNaN(f.v[i])) {
return true;
}
}
@@ -534,12 +532,12 @@
// The jet is normal if all parts of the jet are normal.
template <typename T, int N> inline
-bool isnormal(const Jet<T, N>& f) {
- if (!isnormal(f.a)) {
+bool IsNormal(const Jet<T, N>& f) {
+ if (!IsNormal(f.a)) {
return false;
}
for (int i = 0; i < N; ++i) {
- if (!isnormal(f.v[i])) {
+ if (!IsNormal(f.v[i])) {
return false;
}
}