From 31a0f5ccd42722676d83914536f741cf02e87818 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Tue, 22 Dec 2020 07:20:30 -0800 Subject: 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. --- arith.c | 11 +++++++++-- 1 file 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 { -- cgit v1.2.3