summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreschnett <eschnett@17b73243-c579-4c4c-a9d2-2d5706c11dac>2014-04-19 10:59:05 +0000
committereschnett <eschnett@17b73243-c579-4c4c-a9d2-2d5706c11dac>2014-04-19 10:59:05 +0000
commit568c2e3b24c630b01e0f3d4c62a536756c1fc561 (patch)
tree7abf8351b062e6485cbcacc2bc3725b80ba788f4
parentb9ccfb348184402ee856f6230b66840ab1ec1b64 (diff)
Provide always-working isnan etc.
Certain math optimization options (e.g. -ffast-math) tell the compiler that IEEE floating point numbers such as inf and nan do not need to be handled correctly (in the sense specified by the IEEE standard). This greatly improves floating-point speed and is commonly used in numerical HPC applications. However, since compilers then don't need to handle inf and nan correctly, they have begun to optimise isnan(x) to simply returning false all the time. This improves speed (since the check does not actually need to occur) and reduces code size (since the nan-handling if branches can be omitted). Of course, this makes it then impossible to actually check for nan by calling isnan. Currently, e.g. g++ performs this optimisation, whereas gcc does not. Things vary with other compilers. In the future, with link-time optimisations, I expect other compilers to follow g++. This patch provides functions CCTK_IEEE_isnan etc. that always check for nan, independent of the chosen optimisation flags. git-svn-id: http://svn.cactuscode.org/flesh/trunk@5107 17b73243-c579-4c4c-a9d2-2d5706c11dac
-rw-r--r--src/include/cctk_Math.h7
-rw-r--r--src/util/Math.c84
2 files changed, 91 insertions, 0 deletions
diff --git a/src/include/cctk_Math.h b/src/include/cctk_Math.h
index e51c991f..5bc29b59 100644
--- a/src/include/cctk_Math.h
+++ b/src/include/cctk_Math.h
@@ -41,6 +41,13 @@ int CCTK_isnan(double x);
int CCTK_isnormal(double x);
int CCTK_signbit(double x);
+ /* int CCTK_IEEE_fpclassify(double x); */
+int CCTK_IEEE_isfinite(double x);
+int CCTK_IEEE_isinf(double x);
+int CCTK_IEEE_isnan(double x);
+int CCTK_IEEE_isnormal(double x);
+int CCTK_IEEE_signbit(double x);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/util/Math.c b/src/util/Math.c
index 7ce8d680..dbc146ad 100644
--- a/src/util/Math.c
+++ b/src/util/Math.c
@@ -10,6 +10,8 @@
@@*/
#include <math.h>
+#include <stdint.h>
+#include <string.h>
#include <cctk_Config.h>
#include <cctk_Math.h>
@@ -131,3 +133,85 @@ int CCTK_FNAME(CCTK_signbit)(double *x)
{
return CCTK_signbit(*x);
}
+
+
+
+int CCTK_IEEE_isfinite(double x)
+{
+ uint64_t u;
+ memcpy(&u, &x, sizeof u);
+ uint64_t e = (u & UINT64_C(0x7ff0000000000000)) >> 52;
+ return e != UINT64_C(0x7ff);
+}
+
+int CCTK_FNAME(CCTK_IEEE_isfinite)(double *x);
+int CCTK_FNAME(CCTK_IEEE_isfinite)(double *x)
+{
+ return CCTK_IEEE_isfinite(*x);
+}
+
+
+
+int CCTK_IEEE_isinf(double x)
+{
+ uint64_t u;
+ memcpy(&u, &x, sizeof u);
+ uint64_t e = (u & UINT64_C(0x7ff0000000000000)) >> 52;
+ uint64_t m = u & UINT64_C(0x000fffffffffffff);
+ return e == UINT64_C(0x7ff) && m == 0;
+}
+
+int CCTK_FNAME(CCTK_IEEE_isinf)(double *x);
+int CCTK_FNAME(CCTK_IEEE_isinf)(double *x)
+{
+ return CCTK_IEEE_isinf(*x);
+}
+
+
+
+int CCTK_IEEE_isnan(double x)
+{
+ uint64_t u;
+ memcpy(&u, &x, sizeof u);
+ uint64_t e = (u & UINT64_C(0x7ff0000000000000)) >> 52;
+ uint64_t m = u & UINT64_C(0x000fffffffffffff);
+ return e == UINT64_C(0x7ff) && m != 0;
+}
+
+int CCTK_FNAME(CCTK_IEEE_isnan)(double *x);
+int CCTK_FNAME(CCTK_IEEE_isnan)(double *x)
+{
+ return CCTK_IEEE_isnan(*x);
+}
+
+
+
+int CCTK_IEEE_isnormal(double x)
+{
+ uint64_t u;
+ memcpy(&u, &x, sizeof u);
+ uint64_t e = (u & UINT64_C(0x7ff0000000000000)) >> 52;
+ return e != 0 && e != UINT64_C(0x7ff);
+}
+
+int CCTK_FNAME(CCTK_IEEE_isnormal)(double *x);
+int CCTK_FNAME(CCTK_IEEE_isnormal)(double *x)
+{
+ return CCTK_IEEE_isnormal(*x);
+}
+
+
+
+int CCTK_IEEE_signbit(double x)
+{
+ uint64_t u;
+ memcpy(&u, &x, sizeof u);
+ uint64_t s = (u & UINT64_C(0x8000000000000000)) >> 63;
+ return s;
+}
+
+int CCTK_FNAME(CCTK_IEEE_signbit)(double *x);
+int CCTK_FNAME(CCTK_IEEE_signbit)(double *x)
+{
+ return CCTK_IEEE_signbit(*x);
+}