comparison src/number-mp.c @ 5736:3192994c49ca

Convert C (un)signed long long values to bignums properly. This patch also does the following: - Uses make_fixnum instead of make_integer when the argument is guaranteed to be in the fixnum range. - Introduces make_unsigned_integer so that we handle unsigned values with the high bit set correctly. - Introduces conversions between bignums and (un)signed long long values. - Uses mp_set_memory_functions with the BSD MP code, if it exists. - Eliminates some unnecessary consing in the Lisp + and * implementations. - Fixes a problem with check_valid_xbm_inline(). This function is called during intialization. It calls Ftimes. When using pdump, this is a problem, because (a) the bignum code is not initialized until *after* dumping, so we don't try to dump any bignums, and (b) multiplication of integers is done inside bignums so we handle fixnum overflow correctly. I decided that an XBM file with dimensions that don't fit into fixnums is probably not something we want to try to handle anyway, and did the arithmetic with C values instead of Lisp values. Doing that broke one test, which started getting a different error message from the one it expected, so I adjusted the test to match the new reality. - Fixes a few miscellaneous bugs in the BSD MP code. See <CAHCOHQk0u0=eD1fUMHTNWi2Yh=1WgiYyCXdMbsGzHBNhdqYz4w@mail.gmail.com> in xemacs-patches, as well as followup messages.
author Jerry James <james@xemacs.org>
date Mon, 17 Jun 2013 10:23:00 -0600
parents 7aa144d1404b
children a2912073be85
comparison
equal deleted inserted replaced
5735:ff13c44ce0d9 5736:3192994c49ca
19 /* Synched up with: Not in FSF. */ 19 /* Synched up with: Not in FSF. */
20 20
21 #include <config.h> 21 #include <config.h>
22 #include <limits.h> 22 #include <limits.h>
23 #include <math.h> 23 #include <math.h>
24 #include <stdlib.h>
24 #include "lisp.h" 25 #include "lisp.h"
25 26
26 static MINT *bignum_bytesize, *bignum_long_sign_bit, *bignum_one, *bignum_two; 27 static MINT *bignum_bytesize, *bignum_one, *bignum_two;
27 MINT *bignum_zero, *intern_bignum; 28 MINT *bignum_zero, *intern_bignum;
28 MINT *bignum_min_int, *bignum_max_int, *bignum_max_uint; 29 MINT *bignum_min_int, *bignum_max_int, *bignum_max_uint;
29 MINT *bignum_min_long, *bignum_max_long, *bignum_max_ulong; 30 MINT *bignum_min_long, *bignum_max_long, *bignum_max_ulong;
31 MINT *bignum_min_llong, *bignum_max_llong, *bignum_max_ullong;
30 short div_rem; 32 short div_rem;
31 33
32 char * 34 char *
33 bignum_to_string (bignum b, int base) 35 bignum_to_string (bignum b, int base)
34 { 36 {
162 sign = bignum_sign (b); 164 sign = bignum_sign (b);
163 BIGNUM_TO_TYPE (unsigned long, unsigned long); 165 BIGNUM_TO_TYPE (unsigned long, unsigned long);
164 return retval; 166 return retval;
165 } 167 }
166 168
169 long long
170 bignum_to_llong (bignum b)
171 {
172 short rem, sign;
173 unsigned long long retval = 0LL;
174 REGISTER unsigned int i;
175 MINT *quo;
176
177 sign = bignum_sign (b);
178 BIGNUM_TO_TYPE (long long, unsigned long long);
179 return ((long long) retval) * sign;
180 }
181
182 unsigned long long
183 bignum_to_ullong (bignum b)
184 {
185 short rem, sign;
186 unsigned long long retval = 0UL;
187 REGISTER unsigned int i;
188 MINT *quo;
189
190 sign = bignum_sign (b);
191 BIGNUM_TO_TYPE (unsigned long long, unsigned long long);
192 return retval;
193 }
194
167 double 195 double
168 bignum_to_double (bignum b) 196 bignum_to_double (bignum b)
169 { 197 {
170 short rem, sign; 198 short rem, sign;
171 double retval = 0.0, factor = 1.0; 199 double retval = 0.0, factor = 1.0;
247 MP_MULT (b, mbase, b); 275 MP_MULT (b, mbase, b);
248 temp = MP_ITOM (digit); 276 temp = MP_ITOM (digit);
249 MP_MADD (b, temp, b); 277 MP_MADD (b, temp, b);
250 MP_MFREE (temp); 278 MP_MFREE (temp);
251 } 279 }
280 MP_MFREE (mbase);
252 281
253 if (neg) 282 if (neg)
254 MP_MSUB (bignum_zero, b, b); 283 MP_MSUB (bignum_zero, b, b);
255 284
256 return (digit >= 0) ? -1 : 0; 285 return (digit >= 0) ? -1 : 0;
257 } 286 }
258 287
259 void 288 void
260 bignum_set_long (MINT *b, long l) 289 bignum_set_long (bignum b, long l)
261 { 290 {
262 /* Negative l is hard, not least because -LONG_MIN == LONG_MIN. We pretend 291 char hex[SIZEOF_LONG * 2U + 2U];
263 that l is unsigned, then subtract off the amount equal to the sign bit. */ 292 MINT *temp;
264 bignum_set_ulong (b, (unsigned long) l); 293 int neg = l < 0L;
265 if (l < 0L) 294
266 MP_MSUB (b, bignum_long_sign_bit, b); 295 snprintf (hex, SIZEOF_LONG * 2U + 2U, "%lx",
296 neg ? (unsigned long) -l : (unsigned long) l);
297 temp = MP_XTOM (hex);
298 if (neg)
299 MP_MSUB (bignum_zero, temp, b);
300 else
301 MP_MOVE (temp, b);
302 MP_MFREE (temp);
267 } 303 }
268 304
269 void 305 void
270 bignum_set_ulong (bignum b, unsigned long l) 306 bignum_set_ulong (bignum b, unsigned long l)
271 { 307 {
272 REGISTER unsigned int i; 308 char hex[SIZEOF_LONG * 2U + 2U];
273 MINT *multiplier = MP_ITOM (1); 309 MINT *temp;
274 310
275 MP_MOVE (bignum_zero, b); 311 snprintf (hex, SIZEOF_LONG * 2U + 2U, "%lx", l);
276 for (i = 0UL; l > 0UL; l >>= 8, i++) 312 temp = MP_XTOM (hex);
277 { 313 MP_MOVE (temp, b);
278 MINT *temp = MP_ITOM ((short) (l & 255)); 314 MP_MFREE (temp);
279 MP_MULT (multiplier, temp, temp); 315 }
280 MP_MADD (b, temp, b); 316
281 MP_MULT (multiplier, bignum_bytesize, multiplier); 317 void
282 MP_MFREE (temp); 318 bignum_set_llong (bignum b, long long l)
283 } 319 {
284 MP_MFREE (multiplier); 320 char hex[SIZEOF_LONG_LONG * 2U + 2U];
321 MINT *temp;
322 int neg = l < 0LL;
323
324 snprintf (hex, SIZEOF_LONG_LONG * 2U + 2U, "%llx",
325 neg ? (unsigned long long) -l : (unsigned long long) l);
326 temp = MP_XTOM (hex);
327 if (neg)
328 MP_MSUB (bignum_zero, temp, b);
329 else
330 MP_MOVE (temp, b);
331 MP_MFREE (temp);
332 }
333
334 void
335 bignum_set_ullong (bignum b, unsigned long long l)
336 {
337 char hex[SIZEOF_LONG_LONG * 2U + 2U];
338 MINT *temp;
339
340 snprintf (hex, SIZEOF_LONG_LONG * 2U + 2U, "%llx", l);
341 temp = MP_XTOM (hex);
342 MP_MOVE (temp, b);
343 MP_MFREE (temp);
285 } 344 }
286 345
287 void 346 void
288 bignum_set_double (bignum b, double d) 347 bignum_set_double (bignum b, double d)
289 { 348 {
483 void 542 void
484 bignum_clrbit (bignum b, unsigned long bit) 543 bignum_clrbit (bignum b, unsigned long bit)
485 { 544 {
486 MINT *num = MP_ITOM (0); 545 MINT *num = MP_ITOM (0);
487 546
488 /* See if the bit is already set, and subtract it off if not */ 547 /* See if the bit is set, and subtract it off if so */
489 MP_MOVE (b, intern_bignum); 548 MP_MOVE (b, intern_bignum);
490 bignum_pow (num, bignum_two, bit); 549 bignum_pow (num, bignum_two, bit);
491 bignum_ior (intern_bignum, intern_bignum, num); 550 bignum_ior (intern_bignum, intern_bignum, num);
492 if (MP_MCMP (b, intern_bignum) == 0) 551 if (MP_MCMP (b, intern_bignum) == 0)
493 MP_MSUB (b, num, b); 552 MP_MSUB (b, num, b);
514 { 573 {
515 bignum_pow (intern_bignum, bignum_two, bits); 574 bignum_pow (intern_bignum, bignum_two, bits);
516 MP_MDIV (b, intern_bignum, result, intern_bignum); 575 MP_MDIV (b, intern_bignum, result, intern_bignum);
517 } 576 }
518 577
519 void bignum_random_seed(unsigned long seed) 578 void
520 { 579 bignum_random (bignum result, bignum limit)
521 /* FIXME: Implement me */ 580 {
522 } 581 MINT *denominator = MP_ITOM (0), *divisor = MP_ITOM (0);
523 582 bignum_set_long (denominator, RAND_MAX);
524 void bignum_random(bignum result, bignum limit) 583 MP_MADD (denominator, bignum_one, denominator);
525 { 584 MP_MADD (limit, bignum_one, divisor);
526 /* FIXME: Implement me */ 585 MP_MDIV (denominator, divisor, denominator, intern_bignum);
527 MP_MOVE (bignum_zero, result); 586 MP_MFREE (divisor);
528 } 587
588 do
589 {
590 MINT *limitcmp = MP_ITOM (1);
591
592 /* Accumulate at least as many random bits as in LIMIT */
593 MP_MOVE (bignum_zero, result);
594 do
595 {
596 bignum_lshift (limitcmp, limitcmp, FIXNUM_VALBITS);
597 bignum_lshift (result, result, FIXNUM_VALBITS);
598 bignum_set_long (intern_bignum, get_random ());
599 MP_MADD (intern_bignum, result, result);
600 }
601 while (MP_MCMP (limitcmp, limit) <= 0);
602 MP_MDIV (result, denominator, result, intern_bignum);
603 MP_MFREE (limitcmp);
604 }
605 while (MP_MCMP (limit, result) <= 0);
606
607 MP_MFREE (denominator);
608 }
609
610 #ifdef HAVE_MP_SET_MEMORY_FUNCTIONS
611 /* We need the next two functions due to the extra parameter. */
612 static void *
613 mp_realloc (void *ptr, size_t UNUSED (old_size), size_t new_size)
614 {
615 return xrealloc (ptr, new_size);
616 }
617
618 static void
619 mp_free (void *ptr, size_t UNUSED (size))
620 {
621 xfree (ptr);
622 }
623 #endif
529 624
530 void 625 void
531 init_number_mp () 626 init_number_mp ()
532 { 627 {
533 REGISTER unsigned int i; 628 #ifdef HAVE_MP_SET_MEMORY_FUNCTIONS
629 mp_set_memory_functions ((void *(*) (size_t)) xmalloc, mp_realloc, mp_free);
630 #endif
534 631
535 bignum_zero = MP_ITOM (0); 632 bignum_zero = MP_ITOM (0);
536 bignum_one = MP_ITOM (1); 633 bignum_one = MP_ITOM (1);
537 bignum_two = MP_ITOM (2); 634 bignum_two = MP_ITOM (2);
538 635
539 /* intern_bignum holds throwaway values from macro expansions in 636 /* intern_bignum holds throwaway values from macro expansions in
540 number-mp.h. Its value is immaterial. */ 637 number-mp.h. Its value is immaterial. */
541 intern_bignum = MP_ITOM (0); 638 intern_bignum = MP_ITOM (0);
542 639
543 /* bignum_bytesize holds the number of bits in a byte. */ 640 /* The multiplier used to shift a number left by one byte's worth of bits */
544 bignum_bytesize = MP_ITOM (256); 641 bignum_bytesize = MP_ITOM (256);
545
546 /* bignum_long_sign_bit holds an adjustment for negative longs. */
547 bignum_long_sign_bit = MP_ITOM (256);
548 for (i = 1UL; i < sizeof (long); i++)
549 MP_MULT (bignum_bytesize, bignum_long_sign_bit, bignum_long_sign_bit);
550 642
551 /* The MP interface only supports turning short ints into MINTs, so we have 643 /* The MP interface only supports turning short ints into MINTs, so we have
552 to set these the hard way. */ 644 to set these the hard way. */
553 645
554 bignum_min_int = MP_ITOM (0); 646 bignum_min_int = MP_ITOM (0);
566 bignum_max_long = MP_ITOM (0); 658 bignum_max_long = MP_ITOM (0);
567 bignum_set_long (bignum_max_long, LONG_MAX); 659 bignum_set_long (bignum_max_long, LONG_MAX);
568 660
569 bignum_max_ulong = MP_ITOM (0); 661 bignum_max_ulong = MP_ITOM (0);
570 bignum_set_ulong (bignum_max_ulong, ULONG_MAX); 662 bignum_set_ulong (bignum_max_ulong, ULONG_MAX);
571 } 663
664 bignum_min_llong = MP_ITOM (0);
665 bignum_set_llong (bignum_min_llong, LLONG_MIN);
666
667 bignum_max_llong = MP_ITOM (0);
668 bignum_set_llong (bignum_max_llong, LLONG_MAX);
669
670 bignum_max_ullong = MP_ITOM (0);
671 bignum_set_ullong (bignum_max_ullong, ULLONG_MAX);
672 }