summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2015-12-03 19:06:49 -0500
committerSteve Hay <steve.m.hay@googlemail.com>2015-12-07 00:42:45 +0000
commit13353b81126c1ad697c0450811a5d5c47eed896e (patch)
tree0ba3d9a68bf078a50960d6c740fc726aa18c998b
parent51b08a51ddedbde437e8f79b55ab9f6313b0c58a (diff)
downloadperl-13353b81126c1ad697c0450811a5d5c47eed896e.tar.gz
Have more fallbacks for our signbit() emulation.
These help in systems which do not have signbit(), or fail to find one, or which explicitly disable it. The idea for the fallback implementation from Craig Berry. (cherry picked from commit 572cd85091706ffa2e19db60c41c6bb106297e3a)
-rw-r--r--numeric.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/numeric.c b/numeric.c
index be85adb3ea..2e7d45ef70 100644
--- a/numeric.c
+++ b/numeric.c
@@ -1632,8 +1632,22 @@ Perl_signbit(NV x) {
# ifdef Perl_fp_class_nzero
if (x == 0)
return Perl_fp_class_nzero(x);
-# endif
+ /* Try finding the high byte, and assume it's highest
+ * bit is the sign. This assumption is probably wrong
+ * somewhere. */
+# elif defined(USE_LONG_DOUBLE) && LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_LITTLE_ENDIAN
+ return (((unsigned char *)&x)[9] & 0x80);
+# elif defined(NV_LITTLE_ENDIAN)
+ /* Note that NVSIZE is sizeof(NV), which would make the below be
+ * wrong if the end bytes are unused, which happens with the x86
+ * 80-bit long doubles, which is why take care of that above. */
+ return (((unsigned char *)&x)[NVSIZE - 1] & 0x80);
+# elif defined(NV_BIG_ENDIAN)
+ return (((unsigned char *)&x)[0] & 0x80);
+# else
+ /* This last fallback will fail for the negative zero. */
return (x < 0.0) ? 1 : 0;
+# endif
}
#endif