summaryrefslogtreecommitdiff
path: root/numeric.c
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2015-12-03 19:06:49 -0500
committerJarkko Hietaniemi <jhi@iki.fi>2015-12-03 21:12:06 -0500
commit572cd85091706ffa2e19db60c41c6bb106297e3a (patch)
tree064d202edc7203487e0a4b263982ed2ddc772259 /numeric.c
parent50774986f96b2af8349e6259cf86ff2d2aeaef2f (diff)
downloadperl-572cd85091706ffa2e19db60c41c6bb106297e3a.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.
Diffstat (limited to 'numeric.c')
-rw-r--r--numeric.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/numeric.c b/numeric.c
index 90b586dccd..9cf6f6f523 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