diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2020-12-22 07:20:30 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-12-22 07:20:30 -0800 |
commit | 16017b64feb3a191d42c936e1bd0d483cdaf4f60 (patch) | |
tree | c4d2c72867274ec78fe80e27d036e3b6ce863163 | |
parent | 99d2eedbe9c1549c4ebd990e590d8a6a1c1ae588 (diff) | |
download | txr-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.
-rw-r--r-- | arith.c | 11 |
1 files changed, 9 insertions, 2 deletions
@@ -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 { |