aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2019-11-14 18:51:17 -0800
committerPaul Eggert2019-11-14 18:52:48 -0800
commit8b848def9bc3c4ad786670d0447a6fb396f2ff30 (patch)
treeb7343d7e0c5ae80efc702e23c0b2037c8693d96a /src
parent6ea1e35f6f8b89b979e660bf04bda1757c0cdff0 (diff)
downloademacs-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.c29
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
347int 346int
348double_integer_scale (double d) 347double_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));