From c44bc4d370b38ac3e9da15579fd372d1410d4b4c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 13 Sep 2018 14:28:56 -0700 Subject: Fix (floor 54043195528445955 3.0) bug * src/floatfns.c (rounding_driver): Fix rounding error that can occur when both args have values exactly representable as integers but at least one arg is a float. * test/src/floatfns-tests.el (big-round): New test. --- src/floatfns.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'src/floatfns.c') diff --git a/src/floatfns.c b/src/floatfns.c index 6f5aee2db9d..900392575c0 100644 --- a/src/floatfns.c +++ b/src/floatfns.c @@ -332,6 +332,18 @@ This is the same as the exponent of a float. */) return make_fixnum (value); } +/* True if A is exactly representable as an integer. */ + +static bool +integer_value (Lisp_Object a) +{ + if (FLOATP (a)) + { + double d = XFLOAT_DATA (a); + return d == floor (d) && isfinite (d); + } + return true; +} /* the rounding functions */ @@ -353,10 +365,16 @@ rounding_driver (Lisp_Object arg, Lisp_Object divisor, else { CHECK_NUMBER (divisor); - if (!FLOATP (arg) && !FLOATP (divisor)) + if (integer_value (arg) && integer_value (divisor)) { /* Divide as integers. Converting to double might lose info, even for fixnums; also see the FIXME below. */ + + if (FLOATP (arg)) + arg = double_to_integer (XFLOAT_DATA (arg)); + if (FLOATP (divisor)) + divisor = double_to_integer (XFLOAT_DATA (divisor)); + if (FIXNUMP (divisor)) { if (XFIXNUM (divisor) == 0) -- cgit v1.2.3