aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2018-09-22 08:59:06 -0700
committerPaul Eggert2018-09-22 09:01:26 -0700
commit0b36041d2a528419982a19940573783ff318c0d4 (patch)
tree0b66b534356f9e4ed7cb39601f6d29492cbea104 /src
parent596ccc087c8f844f81b075da643e5c554a8de9d6 (diff)
downloademacs-0b36041d2a528419982a19940573783ff318c0d4.tar.gz
emacs-0b36041d2a528419982a19940573783ff318c0d4.zip
Round bignums consistently with other integers
* src/bignum.c (mpz_bufsize): New function. (bignum_bufsize): Use it. (mpz_get_d_rounded): New function. (bignum_to_double): Use it. * src/bignum.c (bignum_to_double): * src/data.c (bignum_arith_driver): When converting bignums to double, round instead of truncating, to be consistent with what happens with fixnums. * test/src/floatfns-tests.el (bignum-to-float): Test rounding.
Diffstat (limited to 'src')
-rw-r--r--src/bignum.c34
-rw-r--r--src/bignum.h1
-rw-r--r--src/data.c2
3 files changed, 33 insertions, 4 deletions
diff --git a/src/bignum.c b/src/bignum.c
index 5e86c404b70..1e78d981b7d 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -62,7 +62,7 @@ init_bignum (void)
62double 62double
63bignum_to_double (Lisp_Object n) 63bignum_to_double (Lisp_Object n)
64{ 64{
65 return mpz_get_d (XBIGNUM (n)->value); 65 return mpz_get_d_rounded (XBIGNUM (n)->value);
66} 66}
67 67
68/* Return D, converted to a Lisp integer. Discard any fraction. 68/* Return D, converted to a Lisp integer. Discard any fraction.
@@ -251,12 +251,40 @@ bignum_to_uintmax (Lisp_Object x)
251} 251}
252 252
253/* Yield an upper bound on the buffer size needed to contain a C 253/* Yield an upper bound on the buffer size needed to contain a C
254 string representing the bignum NUM in base BASE. This includes any 254 string representing the NUM in base BASE. This includes any
255 preceding '-' and the terminating null. */ 255 preceding '-' and the terminating null. */
256static ptrdiff_t
257mpz_bufsize (mpz_t const num, int base)
258{
259 return mpz_sizeinbase (num, base) + 2;
260}
256ptrdiff_t 261ptrdiff_t
257bignum_bufsize (Lisp_Object num, int base) 262bignum_bufsize (Lisp_Object num, int base)
258{ 263{
259 return mpz_sizeinbase (XBIGNUM (num)->value, base) + 2; 264 return mpz_bufsize (XBIGNUM (num)->value, base);
265}
266
267/* Convert NUM to a nearest double, as opposed to mpz_get_d which
268 truncates toward zero. */
269double
270mpz_get_d_rounded (mpz_t const num)
271{
272 ptrdiff_t size = mpz_bufsize (num, 10);
273
274 /* Use mpz_get_d as a shortcut for a bignum so small that rounding
275 errors cannot occur, which is possible if EMACS_INT (not counting
276 sign) has fewer bits than a double significand. */
277 if (! ((FLT_RADIX == 2 && DBL_MANT_DIG <= FIXNUM_BITS - 1)
278 || (FLT_RADIX == 16 && DBL_MANT_DIG * 4 <= FIXNUM_BITS - 1))
279 && size <= DBL_DIG + 2)
280 return mpz_get_d (num);
281
282 USE_SAFE_ALLOCA;
283 char *buf = SAFE_ALLOCA (size);
284 mpz_get_str (buf, 10, num);
285 double result = strtod (buf, NULL);
286 SAFE_FREE ();
287 return result;
260} 288}
261 289
262/* Store into BUF (of size SIZE) the value of NUM as a base-BASE string. 290/* Store into BUF (of size SIZE) the value of NUM as a base-BASE string.
diff --git a/src/bignum.h b/src/bignum.h
index 65515493436..e9cd5c07635 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -46,6 +46,7 @@ extern mpz_t mpz[4];
46extern void init_bignum (void); 46extern void init_bignum (void);
47extern Lisp_Object make_integer_mpz (void); 47extern Lisp_Object make_integer_mpz (void);
48extern void mpz_set_intmax_slow (mpz_t, intmax_t) ARG_NONNULL ((1)); 48extern void mpz_set_intmax_slow (mpz_t, intmax_t) ARG_NONNULL ((1));
49extern double mpz_get_d_rounded (mpz_t const);
49 50
50INLINE_HEADER_BEGIN 51INLINE_HEADER_BEGIN
51 52
diff --git a/src/data.c b/src/data.c
index cc080372d8b..750d494b83a 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2921,7 +2921,7 @@ bignum_arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args,
2921 CHECK_NUMBER_COERCE_MARKER (val); 2921 CHECK_NUMBER_COERCE_MARKER (val);
2922 if (FLOATP (val)) 2922 if (FLOATP (val))
2923 return float_arith_driver (code, nargs, args, argnum, 2923 return float_arith_driver (code, nargs, args, argnum,
2924 mpz_get_d (*accum), val); 2924 mpz_get_d_rounded (*accum), val);
2925 } 2925 }
2926} 2926}
2927 2927