summaryrefslogtreecommitdiffstats
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
commit31a0f5ccd42722676d83914536f741cf02e87818 (patch)
treec4d2c72867274ec78fe80e27d036e3b6ce863163
parentbf7fc613066771c36c82e7d73bd80c7245c6d618 (diff)
downloadtxr-31a0f5ccd42722676d83914536f741cf02e87818.tar.gz
txr-31a0f5ccd42722676d83914536f741cf02e87818.tar.bz2
txr-31a0f5ccd42722676d83914536f741cf02e87818.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.
-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 {