1 /* Big numbers for Emacs.
3 Copyright 2018 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
29 /* mpz global temporaries. Making them global saves the trouble of
30 properly using mpz_init and mpz_clear on temporaries even when
31 storage is exhausted. Admittedly this is not ideal. An mpz value
32 in a temporary is made permanent by mpz_swapping it with a bignum's
33 value. Although typically at most two temporaries are needed,
34 rounding_driver and rounddiv_q need four altogther. */
39 xrealloc_for_gmp (void *ptr
, size_t ignore
, size_t size
)
41 return xrealloc (ptr
, size
);
45 xfree_for_gmp (void *ptr
, size_t ignore
)
53 eassert (mp_bits_per_limb
== GMP_NUMB_BITS
);
54 integer_width
= 1 << 16;
55 mp_set_memory_functions (xmalloc
, xrealloc_for_gmp
, xfree_for_gmp
);
57 for (int i
= 0; i
< ARRAYELTS (mpz
); i
++)
61 /* Return the value of the Lisp bignum N, as a double. */
63 bignum_to_double (Lisp_Object n
)
65 return mpz_get_d_rounded (XBIGNUM (n
)->value
);
68 /* Return D, converted to a Lisp integer. Discard any fraction.
69 Signal an error if D cannot be converted. */
71 double_to_integer (double d
)
75 mpz_set_d (mpz
[0], d
);
76 return make_integer_mpz ();
79 /* Return a Lisp integer equal to mpz[0], which has BITS bits and which
80 must not be in fixnum range. Set mpz[0] to a junk value. */
82 make_bignum_bits (size_t bits
)
84 /* The documentation says integer-width should be nonnegative, so
85 a single comparison suffices even though 'bits' is unsigned. */
86 if (integer_width
< bits
)
89 struct Lisp_Bignum
*b
= ALLOCATE_PSEUDOVECTOR (struct Lisp_Bignum
, value
,
92 mpz_swap (b
->value
, mpz
[0]);
93 return make_lisp_ptr (b
, Lisp_Vectorlike
);
96 /* Return a Lisp integer equal to mpz[0], which must not be in fixnum range.
97 Set mpz[0] to a junk value. */
101 return make_bignum_bits (mpz_sizeinbase (mpz
[0], 2));
104 static void mpz_set_uintmax_slow (mpz_t
, uintmax_t);
106 /* Set RESULT to V. */
108 mpz_set_uintmax (mpz_t result
, uintmax_t v
)
111 mpz_set_ui (result
, v
);
113 mpz_set_uintmax_slow (result
, v
);
116 /* Return a Lisp integer equal to N, which must not be in fixnum range. */
118 make_bigint (intmax_t n
)
120 eassert (FIXNUM_OVERFLOW_P (n
));
121 mpz_set_intmax (mpz
[0], n
);
122 return make_bignum ();
125 make_biguint (uintmax_t n
)
127 eassert (FIXNUM_OVERFLOW_P (n
));
128 mpz_set_uintmax (mpz
[0], n
);
129 return make_bignum ();
132 /* Return a Lisp integer with value taken from mpz[0].
133 Set mpz[0] to a junk value. */
135 make_integer_mpz (void)
137 size_t bits
= mpz_sizeinbase (mpz
[0], 2);
139 if (bits
<= FIXNUM_BITS
)
142 int i
= 0, shift
= 0;
146 EMACS_INT limb
= mpz_getlimbn (mpz
[0], i
++);
148 shift
+= GMP_NUMB_BITS
;
150 while (shift
< bits
);
152 if (mpz_sgn (mpz
[0]) < 0)
155 if (!FIXNUM_OVERFLOW_P (v
))
156 return make_fixnum (v
);
159 return make_bignum_bits (bits
);
162 /* Set RESULT to V. This code is for when intmax_t is wider than long. */
164 mpz_set_intmax_slow (mpz_t result
, intmax_t v
)
166 int maxlimbs
= (INTMAX_WIDTH
+ GMP_NUMB_BITS
- 1) / GMP_NUMB_BITS
;
167 mp_limb_t
*limb
= mpz_limbs_write (result
, maxlimbs
);
170 bool negative
= v
< 0;
174 u
= -u
& ((two
<< (UINTMAX_WIDTH
- 1)) - 1);
180 u
= GMP_NUMB_BITS
< UINTMAX_WIDTH
? u
>> GMP_NUMB_BITS
: 0;
184 mpz_limbs_finish (result
, negative
? -n
: n
);
187 mpz_set_uintmax_slow (mpz_t result
, uintmax_t v
)
189 int maxlimbs
= (UINTMAX_WIDTH
+ GMP_NUMB_BITS
- 1) / GMP_NUMB_BITS
;
190 mp_limb_t
*limb
= mpz_limbs_write (result
, maxlimbs
);
196 v
= GMP_NUMB_BITS
< INTMAX_WIDTH
? v
>> GMP_NUMB_BITS
: 0;
200 mpz_limbs_finish (result
, n
);
203 /* Return the value of the bignum X if it fits, 0 otherwise.
204 A bignum cannot be zero, so 0 indicates failure reliably. */
206 bignum_to_intmax (Lisp_Object x
)
208 ptrdiff_t bits
= mpz_sizeinbase (XBIGNUM (x
)->value
, 2);
209 bool negative
= mpz_sgn (XBIGNUM (x
)->value
) < 0;
211 if (bits
< INTMAX_WIDTH
)
214 int i
= 0, shift
= 0;
218 intmax_t limb
= mpz_getlimbn (XBIGNUM (x
)->value
, i
++);
220 shift
+= GMP_NUMB_BITS
;
222 while (shift
< bits
);
224 return negative
? -v
: v
;
226 return ((bits
== INTMAX_WIDTH
&& INTMAX_MIN
< -INTMAX_MAX
&& negative
227 && mpz_scan1 (XBIGNUM (x
)->value
, 0) == INTMAX_WIDTH
- 1)
231 bignum_to_uintmax (Lisp_Object x
)
234 if (0 <= mpz_sgn (XBIGNUM (x
)->value
))
236 ptrdiff_t bits
= mpz_sizeinbase (XBIGNUM (x
)->value
, 2);
237 if (bits
<= UINTMAX_WIDTH
)
239 int i
= 0, shift
= 0;
243 uintmax_t limb
= mpz_getlimbn (XBIGNUM (x
)->value
, i
++);
245 shift
+= GMP_NUMB_BITS
;
247 while (shift
< bits
);
253 /* Yield an upper bound on the buffer size needed to contain a C
254 string representing the NUM in base BASE. This includes any
255 preceding '-' and the terminating null. */
257 mpz_bufsize (mpz_t
const num
, int base
)
259 return mpz_sizeinbase (num
, base
) + 2;
262 bignum_bufsize (Lisp_Object num
, int base
)
264 return mpz_bufsize (XBIGNUM (num
)->value
, base
);
267 /* Convert NUM to a nearest double, as opposed to mpz_get_d which
268 truncates toward zero. */
270 mpz_get_d_rounded (mpz_t
const num
)
272 ptrdiff_t size
= mpz_bufsize (num
, 10);
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
);
283 char *buf
= SAFE_ALLOCA (size
);
284 mpz_get_str (buf
, 10, num
);
285 double result
= strtod (buf
, NULL
);
290 /* Store into BUF (of size SIZE) the value of NUM as a base-BASE string.
291 If BASE is negative, use upper-case digits in base -BASE.
292 Return the string's length.
293 SIZE must equal bignum_bufsize (NUM, abs (BASE)). */
295 bignum_to_c_string (char *buf
, ptrdiff_t size
, Lisp_Object num
, int base
)
297 eassert (bignum_bufsize (num
, abs (base
)) == size
);
298 mpz_get_str (buf
, base
, XBIGNUM (num
)->value
);
299 ptrdiff_t n
= size
- 2;
300 return !buf
[n
- 1] ? n
- 1 : n
+ !!buf
[n
];
303 /* Convert NUM to a base-BASE Lisp string.
304 If BASE is negative, use upper-case digits in base -BASE. */
307 bignum_to_string (Lisp_Object num
, int base
)
309 ptrdiff_t size
= bignum_bufsize (num
, abs (base
));
311 char *str
= SAFE_ALLOCA (size
);
312 ptrdiff_t len
= bignum_to_c_string (str
, size
, num
, base
);
313 Lisp_Object result
= make_unibyte_string (str
, len
);
318 /* Create a bignum by scanning NUM, with digits in BASE.
319 NUM must consist of an optional '-', a nonempty sequence
320 of base-BASE digits, and a terminating null byte, and
321 the represented number must not be in fixnum range. */
324 make_bignum_str (char const *num
, int base
)
326 struct Lisp_Bignum
*b
= ALLOCATE_PSEUDOVECTOR (struct Lisp_Bignum
, value
,
329 int check
= mpz_set_str (b
->value
, num
, base
);
330 eassert (check
== 0);
331 return make_lisp_ptr (b
, Lisp_Vectorlike
);