diff options
| author | Paul Eggert | 2019-11-14 18:51:17 -0800 |
|---|---|---|
| committer | Paul Eggert | 2019-11-14 18:52:48 -0800 |
| commit | 8b848def9bc3c4ad786670d0447a6fb396f2ff30 (patch) | |
| tree | b7343d7e0c5ae80efc702e23c0b2037c8693d96a /src | |
| parent | 6ea1e35f6f8b89b979e660bf04bda1757c0cdff0 (diff) | |
| download | emacs-8b848def9bc3c4ad786670d0447a6fb396f2ff30.tar.gz emacs-8b848def9bc3c4ad786670d0447a6fb396f2ff30.zip | |
Handle weird cases like (ceil 0 0.0)
* src/floatfns.c (double_integer_scale): Distinguish Inf from NaN.
(rounding_driver): Handle (ceil 0 0.0) and (ceil 0 1.0e+INF).
* test/src/floatfns-tests.el (special-round): Add tests for
weird cases like this.
Avoid crash with (floor 0 0.0)
* src/floatfns.c (rounding_driver): Signal an arithmetic
error if divisor is 0.0 or -0.0, instead of crashing.
Diffstat (limited to 'src')
| -rw-r--r-- | src/floatfns.c | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/src/floatfns.c b/src/floatfns.c index a626845377a..30526a16443 100644 --- a/src/floatfns.c +++ b/src/floatfns.c | |||
| @@ -340,9 +340,8 @@ This is the same as the exponent of a float. */) | |||
| 340 | representable as a double. | 340 | representable as a double. |
| 341 | 341 | ||
| 342 | Return DBL_MANT_DIG - DBL_MIN_EXP (the maximum possible valid | 342 | Return DBL_MANT_DIG - DBL_MIN_EXP (the maximum possible valid |
| 343 | scale) if D is zero or tiny. Return a value greater than | 343 | scale) if D is zero or tiny. Return one greater than that if |
| 344 | DBL_MANT_DIG - DBL_MIN_EXP if there is conversion trouble; on all | 344 | D is infinite, and two greater than that if D is a NaN. */ |
| 345 | current platforms this can happen only if D is infinite or a NaN. */ | ||
| 346 | 345 | ||
| 347 | int | 346 | int |
| 348 | double_integer_scale (double d) | 347 | double_integer_scale (double d) |
| @@ -351,11 +350,10 @@ double_integer_scale (double d) | |||
| 351 | return (DBL_MIN_EXP - 1 <= exponent && exponent < INT_MAX | 350 | return (DBL_MIN_EXP - 1 <= exponent && exponent < INT_MAX |
| 352 | ? DBL_MANT_DIG - 1 - exponent | 351 | ? DBL_MANT_DIG - 1 - exponent |
| 353 | : (DBL_MANT_DIG - DBL_MIN_EXP | 352 | : (DBL_MANT_DIG - DBL_MIN_EXP |
| 354 | + (exponent == INT_MAX | 353 | + ((exponent == FP_ILOGBNAN |
| 355 | || (exponent == FP_ILOGBNAN | 354 | && (FP_ILOGBNAN != FP_ILOGB0 || isnan (d))) |
| 356 | && (FP_ILOGBNAN != FP_ILOGB0 || isnan (d))) | 355 | ? 2 |
| 357 | || (!IEEE_FLOATING_POINT && exponent == INT_MIN | 356 | : exponent == INT_MAX))); |
| 358 | && (FP_ILOGB0 != INT_MIN || d != 0))))); | ||
| 359 | } | 357 | } |
| 360 | 358 | ||
| 361 | /* Convert the Lisp number N to an integer and return a pointer to the | 359 | /* Convert the Lisp number N to an integer and return a pointer to the |
| @@ -404,6 +402,7 @@ rounding_driver (Lisp_Object n, Lisp_Object d, | |||
| 404 | 402 | ||
| 405 | CHECK_NUMBER (d); | 403 | CHECK_NUMBER (d); |
| 406 | 404 | ||
| 405 | int dscale = 0; | ||
| 407 | if (FIXNUMP (d)) | 406 | if (FIXNUMP (d)) |
| 408 | { | 407 | { |
| 409 | if (XFIXNUM (d) == 0) | 408 | if (XFIXNUM (d) == 0) |
| @@ -413,9 +412,21 @@ rounding_driver (Lisp_Object n, Lisp_Object d, | |||
| 413 | if (FIXNUMP (n)) | 412 | if (FIXNUMP (n)) |
| 414 | return make_int (fixnum_divide (XFIXNUM (n), XFIXNUM (d))); | 413 | return make_int (fixnum_divide (XFIXNUM (n), XFIXNUM (d))); |
| 415 | } | 414 | } |
| 415 | else if (FLOATP (d)) | ||
| 416 | { | ||
| 417 | if (XFLOAT_DATA (d) == 0) | ||
| 418 | xsignal0 (Qarith_error); | ||
| 419 | dscale = double_integer_scale (XFLOAT_DATA (d)); | ||
| 420 | } | ||
| 416 | 421 | ||
| 417 | int nscale = FLOATP (n) ? double_integer_scale (XFLOAT_DATA (n)) : 0; | 422 | int nscale = FLOATP (n) ? double_integer_scale (XFLOAT_DATA (n)) : 0; |
| 418 | int dscale = FLOATP (d) ? double_integer_scale (XFLOAT_DATA (d)) : 0; | 423 | |
| 424 | /* If the numerator is finite and the denominator infinite, the | ||
| 425 | quotient is zero and there is no need to try the impossible task | ||
| 426 | of rescaling the denominator. */ | ||
| 427 | if (dscale == DBL_MANT_DIG - DBL_MIN_EXP + 1 && nscale < dscale) | ||
| 428 | return make_fixnum (0); | ||
| 429 | |||
| 419 | int_divide (mpz[0], | 430 | int_divide (mpz[0], |
| 420 | *rescale_for_division (n, &mpz[0], nscale, dscale), | 431 | *rescale_for_division (n, &mpz[0], nscale, dscale), |
| 421 | *rescale_for_division (d, &mpz[1], dscale, nscale)); | 432 | *rescale_for_division (d, &mpz[1], dscale, nscale)); |