Mercurial > hg > xemacs-beta
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 } |