summaryrefslogtreecommitdiffstats
path: root/arith.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2020-12-22 07:20:30 -0800
committerKaz Kylheku <kaz@kylheku.com>2020-12-22 07:20:30 -0800
commit16017b64feb3a191d42c936e1bd0d483cdaf4f60 (patch)
treec4d2c72867274ec78fe80e27d036e3b6ce863163 /arith.c
parent99d2eedbe9c1549c4ebd990e590d8a6a1c1ae588 (diff)
downloadtxr-16017b64feb3a191d42c936e1bd0d483cdaf4f60.tar.gz
txr-16017b64feb3a191d42c936e1bd0d483cdaf4f60.tar.bz2
txr-16017b64feb3a191d42c936e1bd0d483cdaf4f60.zip
int-flo: bugfix on 64 bit
* arith.c (int_flo): On 64 bit, we incorrectly handle the positive floating-point values which correspond to (expt 2 63) and (expt 2 64). This is because in the range check which detects whether a double value lands into the cnum or ucnum range, the 64 bit INT_PTR_MAX and UINT_PTR_MAX have no exact equivalent in the double type and are being converted to double values which are greater. That then causes the range check to incorrectly include double values that are actually out of range for the conversion to the cnum or ucnum type, causing bogus values. The quickest fix would be to use < comparison for a half-open range, but that sacrifices two double values on 32 bit, unnecessarily sending them to the text-based conversion code. So instead, let's subtract margins from the range constants on 64 bit.
Diffstat (limited to 'arith.c')
-rw-r--r--arith.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/arith.c b/arith.c
index e5d5216c..971be237 100644
--- a/arith.c
+++ b/arith.c
@@ -2913,13 +2913,20 @@ val int_flo(val f)
{
val self = lit("int-flo");
double d = c_flo(f, self);
+#if SIZEOF_PTR >= 8
+ cnum margin = 512;
+ ucnum umargin = 1024;
+#else
+ cnum margin = 0;
+ ucnum umargin = 0;
+#endif
- if (d >= INT_PTR_MIN && d <= INT_PTR_MAX) {
+ if (d >= INT_PTR_MIN && d <= INT_PTR_MAX - margin) {
cnum n = d;
if (n < NUM_MIN || n > NUM_MAX)
return bignum(n);
return num_fast(n);
- } else if (d >= 0 && d <= UINT_PTR_MAX) {
+ } else if (d >= 0 && d <= UINT_PTR_MAX - umargin) {
ucnum n = d;
return unum(n);
} else {