1 // Copyright (C) 1989-94 Massachusetts Institute of Technology
2 // Portions copyright (C) 2004-2008 Slava Pestov
4 // This material was developed by the Scheme project at the Massachusetts
5 // Institute of Technology, Department of Electrical Engineering and
6 // Computer Science. Permission to copy and modify this software, to
7 // redistribute either the original software or a modified version, and
8 // to use this software for any purpose is granted, subject to the
9 // following restrictions and understandings.
11 // 1. Any copy made of this software must include this copyright notice
14 // 2. Users of this software agree to make their best efforts (a) to
15 // return to the MIT Scheme project any improvements or extensions that
16 // they make, so that these may be included in future releases; and (b)
17 // to inform MIT of noteworthy uses of this software.
19 // 3. All materials developed as a consequence of the use of this
20 // software shall duly acknowledge such use, in accordance with the usual
21 // standards of acknowledging credit in academic research.
23 // 4. MIT has made no warrantee or representation that the operation of
24 // this software will be error-free, and MIT is under no obligation to
25 // provide any services, by way of maintenance, update, or otherwise.
27 // 5. In conjunction with products arising from the use of this material,
28 // there shall be no use of the name of the Massachusetts Institute of
29 // Technology nor of any adaptation thereof in any advertising,
30 // promotional, or sales literature without prior written consent from
33 // Changes for Scheme 48:
34 // * - Converted to ANSI.
35 // * - Added bitwise operations.
36 // * - Added s48 to the beginning of all externally visible names.
37 // * - Cached the bignum representations of -1, 0, and 1.
39 // Changes for Factor:
40 // * - Adapt bignumint.h for Factor memory manager
41 // * - Add more bignum <-> C type conversions
42 // * - Remove unused functions
43 // * - Add local variable GC root recording
44 // * - Remove s48 prefix from function names
45 // * - Various fixes for Win64
47 // * - Added bignum_gcd implementation
55 int factor_vm::bignum_equal_p(bignum
* x
, bignum
* y
) {
56 return ((BIGNUM_ZERO_P(x
))
58 : ((!(BIGNUM_ZERO_P(y
))) &&
59 ((BIGNUM_NEGATIVE_P(x
)) ? (BIGNUM_NEGATIVE_P(y
))
60 : (!(BIGNUM_NEGATIVE_P(y
)))) &&
61 (bignum_equal_p_unsigned(x
, y
))));
64 enum bignum_comparison
factor_vm::bignum_compare(bignum
* x
, bignum
* y
) {
65 return ((BIGNUM_ZERO_P(x
)) ? ((BIGNUM_ZERO_P(y
)) ? BIGNUM_COMPARISON_EQUAL
66 : (BIGNUM_NEGATIVE_P(y
))
67 ? BIGNUM_COMPARISON_GREATER
68 : BIGNUM_COMPARISON_LESS
)
70 ? ((BIGNUM_NEGATIVE_P(x
)) ? BIGNUM_COMPARISON_LESS
71 : BIGNUM_COMPARISON_GREATER
)
72 : (BIGNUM_NEGATIVE_P(x
))
73 ? ((BIGNUM_NEGATIVE_P(y
)) ? (bignum_compare_unsigned(y
, x
))
74 : (BIGNUM_COMPARISON_LESS
))
75 : ((BIGNUM_NEGATIVE_P(y
)) ? (BIGNUM_COMPARISON_GREATER
)
76 : (bignum_compare_unsigned(x
, y
))));
80 bignum
* factor_vm::bignum_add(bignum
* x
, bignum
* y
) {
82 (BIGNUM_ZERO_P(x
)) ? (y
) : (BIGNUM_ZERO_P(y
))
84 : ((BIGNUM_NEGATIVE_P(x
))
85 ? ((BIGNUM_NEGATIVE_P(y
)) ? (bignum_add_unsigned(x
, y
, 1))
86 : (bignum_subtract_unsigned(y
, x
)))
87 : ((BIGNUM_NEGATIVE_P(y
)) ? (bignum_subtract_unsigned(x
, y
))
88 : (bignum_add_unsigned(x
, y
, 0)))));
92 bignum
* factor_vm::bignum_subtract(bignum
* x
, bignum
* y
) {
93 return ((BIGNUM_ZERO_P(x
))
94 ? ((BIGNUM_ZERO_P(y
)) ? (y
) : (bignum_new_sign(
95 y
, (!(BIGNUM_NEGATIVE_P(y
))))))
98 : ((BIGNUM_NEGATIVE_P(x
))
99 ? ((BIGNUM_NEGATIVE_P(y
))
100 ? (bignum_subtract_unsigned(y
, x
))
101 : (bignum_add_unsigned(x
, y
, 1)))
102 : ((BIGNUM_NEGATIVE_P(y
))
103 ? (bignum_add_unsigned(x
, y
, 0))
104 : (bignum_subtract_unsigned(x
, y
))))));
108 bignum
*factor_vm::bignum_square(bignum
* x_
)
110 return bignum_multiply(x_
, x_
);
114 bignum
*factor_vm::bignum_square(bignum
* x_
)
116 data_root
<bignum
> x(x_
, this);
118 bignum_length_type length
= (BIGNUM_LENGTH (x
));
119 bignum
* z
= (allot_bignum_zeroed ((length
+ length
), 0));
121 bignum_digit_type
* scan_z
= BIGNUM_START_PTR (z
);
122 bignum_digit_type
* scan_x
= BIGNUM_START_PTR (x
);
123 bignum_digit_type
* end_x
= scan_x
+ length
;
125 for (int i
= 0; i
< length
; ++i
) {
126 bignum_twodigit_type carry
;
127 bignum_twodigit_type f
= BIGNUM_REF (x
, i
);
128 bignum_digit_type
*pz
= scan_z
+ (i
<< 1);
129 bignum_digit_type
*px
= scan_x
+ i
+ 1;
132 *pz
++ = carry
& BIGNUM_DIGIT_MASK
;
133 carry
>>= BIGNUM_DIGIT_LENGTH
;
134 BIGNUM_ASSERT (carry
<= BIGNUM_DIGIT_MASK
);
139 carry
+= *pz
+ *px
++ * f
;
140 *pz
++ = carry
& BIGNUM_DIGIT_MASK
;
141 carry
>>= BIGNUM_DIGIT_LENGTH
;
142 BIGNUM_ASSERT (carry
<= (BIGNUM_DIGIT_MASK
<< 1));
146 *pz
++ = carry
& BIGNUM_DIGIT_MASK
;
147 carry
>>= BIGNUM_DIGIT_LENGTH
;
150 *pz
+= carry
& BIGNUM_DIGIT_MASK
;
151 BIGNUM_ASSERT ((carry
>> BIGNUM_DIGIT_LENGTH
) == 0);
153 return (bignum_trim (z
));
158 bignum
* factor_vm::bignum_multiply(bignum
* x
, bignum
* y
) {
162 return bignum_square(x
);
166 bignum_length_type x_length
= (BIGNUM_LENGTH(x
));
167 bignum_length_type y_length
= (BIGNUM_LENGTH(y
));
168 int negative_p
= ((BIGNUM_NEGATIVE_P(x
)) ? (!(BIGNUM_NEGATIVE_P(y
)))
169 : (BIGNUM_NEGATIVE_P(y
)));
170 if (BIGNUM_ZERO_P(x
))
172 if (BIGNUM_ZERO_P(y
))
175 bignum_digit_type digit
= (BIGNUM_REF(x
, 0));
177 return (bignum_maybe_new_sign(y
, negative_p
));
178 if (digit
< BIGNUM_RADIX_ROOT
)
179 return (bignum_multiply_unsigned_small_factor(y
, digit
, negative_p
));
182 bignum_digit_type digit
= (BIGNUM_REF(y
, 0));
184 return (bignum_maybe_new_sign(x
, negative_p
));
185 if (digit
< BIGNUM_RADIX_ROOT
)
186 return (bignum_multiply_unsigned_small_factor(x
, digit
, negative_p
));
188 return (bignum_multiply_unsigned(x
, y
, negative_p
));
192 void factor_vm::bignum_divide(bignum
* numerator
, bignum
* denominator
,
193 bignum
** quotient
, bignum
** remainder
) {
194 if (BIGNUM_ZERO_P(denominator
)) {
195 divide_by_zero_error();
198 if (BIGNUM_ZERO_P(numerator
)) {
199 (*quotient
) = numerator
;
200 (*remainder
) = numerator
;
202 int r_negative_p
= (BIGNUM_NEGATIVE_P(numerator
));
204 ((BIGNUM_NEGATIVE_P(denominator
)) ? (!r_negative_p
) : r_negative_p
);
205 switch (bignum_compare_unsigned(numerator
, denominator
)) {
206 case BIGNUM_COMPARISON_EQUAL
: {
207 (*quotient
) = (BIGNUM_ONE(q_negative_p
));
208 (*remainder
) = (BIGNUM_ZERO());
211 case BIGNUM_COMPARISON_LESS
: {
212 (*quotient
) = (BIGNUM_ZERO());
213 (*remainder
) = numerator
;
216 case BIGNUM_COMPARISON_GREATER
: {
217 if ((BIGNUM_LENGTH(denominator
)) == 1) {
218 bignum_digit_type digit
= (BIGNUM_REF(denominator
, 0));
220 (*quotient
) = (bignum_maybe_new_sign(numerator
, q_negative_p
));
221 (*remainder
) = (BIGNUM_ZERO());
223 } else if (digit
< BIGNUM_RADIX_ROOT
) {
224 bignum_divide_unsigned_small_denominator(numerator
, digit
, quotient
,
225 remainder
, q_negative_p
,
229 bignum_divide_unsigned_medium_denominator(
230 numerator
, digit
, quotient
, remainder
, q_negative_p
,
235 bignum_divide_unsigned_large_denominator(
236 numerator
, denominator
, quotient
, remainder
, q_negative_p
,
245 bignum
* factor_vm::bignum_quotient(bignum
* numerator
, bignum
* denominator
) {
246 if (BIGNUM_ZERO_P(denominator
)) {
247 divide_by_zero_error();
248 return (BIGNUM_OUT_OF_BAND
);
250 if (BIGNUM_ZERO_P(numerator
))
254 ((BIGNUM_NEGATIVE_P(denominator
)) ? (!(BIGNUM_NEGATIVE_P(numerator
)))
255 : (BIGNUM_NEGATIVE_P(numerator
)));
256 switch (bignum_compare_unsigned(numerator
, denominator
)) {
257 case BIGNUM_COMPARISON_EQUAL
:
258 return (BIGNUM_ONE(q_negative_p
));
259 case BIGNUM_COMPARISON_LESS
:
260 return (BIGNUM_ZERO());
261 case BIGNUM_COMPARISON_GREATER
:
262 default: // to appease gcc -Wall
265 if ((BIGNUM_LENGTH(denominator
)) == 1) {
266 bignum_digit_type digit
= (BIGNUM_REF(denominator
, 0));
268 return (bignum_maybe_new_sign(numerator
, q_negative_p
));
269 if (digit
< BIGNUM_RADIX_ROOT
)
270 bignum_divide_unsigned_small_denominator(
271 numerator
, digit
, ("ient
), ((bignum
**)0), q_negative_p
, 0);
273 bignum_divide_unsigned_medium_denominator(
274 numerator
, digit
, ("ient
), ((bignum
**)0), q_negative_p
, 0);
276 bignum_divide_unsigned_large_denominator(
277 numerator
, denominator
, ("ient
), ((bignum
**)0), q_negative_p
,
286 bignum
* factor_vm::bignum_remainder(bignum
* numerator
, bignum
* denominator
) {
287 if (BIGNUM_ZERO_P(denominator
)) {
288 divide_by_zero_error();
289 return (BIGNUM_OUT_OF_BAND
);
291 if (BIGNUM_ZERO_P(numerator
))
293 switch (bignum_compare_unsigned(numerator
, denominator
)) {
294 case BIGNUM_COMPARISON_EQUAL
:
295 return (BIGNUM_ZERO());
296 case BIGNUM_COMPARISON_LESS
:
298 case BIGNUM_COMPARISON_GREATER
:
299 default: // to appease gcc -Wall
302 if ((BIGNUM_LENGTH(denominator
)) == 1) {
303 bignum_digit_type digit
= (BIGNUM_REF(denominator
, 0));
305 return (BIGNUM_ZERO());
306 if (digit
< BIGNUM_RADIX_ROOT
)
307 return (bignum_remainder_unsigned_small_denominator(
308 numerator
, digit
, (BIGNUM_NEGATIVE_P(numerator
))));
309 bignum_divide_unsigned_medium_denominator(
310 numerator
, digit
, ((bignum
**)0), (&remainder
), 0,
311 (BIGNUM_NEGATIVE_P(numerator
)));
313 bignum_divide_unsigned_large_denominator(
314 numerator
, denominator
, ((bignum
**)0), (&remainder
), 0,
315 (BIGNUM_NEGATIVE_P(numerator
)));
321 // cell_to_bignum, fixnum_to_bignum, long_long_to_bignum, ulong_long_to_bignum
324 #define FOO_TO_BIGNUM(name, type, stype, utype) \
325 bignum* factor_vm::name##_to_bignum(type n) { \
327 /* Special cases win when these small constants are cached. */ \
329 return (BIGNUM_ZERO()); \
331 return (BIGNUM_ONE(0)); \
332 if (n < (type) 0 && n == (type) - 1) \
333 return (BIGNUM_ONE(1)); \
335 utype accumulator = \
336 ((negative_p = (n < (type) 0)) ? ((type)(-(stype) n)) : n); \
337 if (accumulator < BIGNUM_RADIX) \
339 bignum* result = allot_bignum(1, negative_p); \
340 bignum_digit_type* scan = (BIGNUM_START_PTR(result)); \
341 *scan = (accumulator & BIGNUM_DIGIT_MASK); \
344 bignum_digit_type result_digits[BIGNUM_DIGITS_FOR(type)]; \
345 bignum_digit_type* end_digits = result_digits; \
347 (*end_digits++) = (accumulator & BIGNUM_DIGIT_MASK); \
348 accumulator >>= BIGNUM_DIGIT_LENGTH; \
349 } while (accumulator != 0); \
351 (allot_bignum((end_digits - result_digits), negative_p)); \
352 bignum_digit_type* scan_digits = result_digits; \
353 bignum_digit_type* scan_result = (BIGNUM_START_PTR(result)); \
354 while (scan_digits < end_digits) \
355 (*scan_result++) = (*scan_digits++); \
361 FOO_TO_BIGNUM(cell
, cell
, fixnum
, cell
)
362 FOO_TO_BIGNUM(fixnum
, fixnum
, fixnum
, cell
)
363 FOO_TO_BIGNUM(long_long
, int64_t, int64_t, uint64_t)
364 FOO_TO_BIGNUM(ulong_long
, uint64_t, int64_t, uint64_t)
366 // cannot allocate memory
367 // bignum_to_cell, fixnum_to_cell, long_long_to_cell, ulong_long_to_cell
368 #define BIGNUM_TO_FOO(name, type, stype, utype) \
369 type bignum_to_##name(bignum* bn) { \
370 if (BIGNUM_ZERO_P(bn)) \
373 utype accumulator = 0; \
374 bignum_digit_type* start = (BIGNUM_START_PTR(bn)); \
375 bignum_digit_type* scan = (start + (BIGNUM_LENGTH(bn))); \
376 while (start < scan) \
377 accumulator = ((accumulator << BIGNUM_DIGIT_LENGTH) + (*--scan)); \
378 return ((BIGNUM_NEGATIVE_P(bn)) ? ((type)(-(stype) accumulator)) \
383 BIGNUM_TO_FOO(cell
, cell
, fixnum
, cell
)
384 BIGNUM_TO_FOO(fixnum
, fixnum
, fixnum
, cell
)
385 BIGNUM_TO_FOO(long_long
, int64_t, int64_t, uint64_t)
386 BIGNUM_TO_FOO(ulong_long
, uint64_t, int64_t, uint64_t)
388 bool bignum_fits_fixnum_p(bignum
* bn
) {
389 fixnum len
= BIGNUM_LENGTH(bn
);
394 bignum_digit_type dig
= BIGNUM_START_PTR(bn
)[0];
395 return (BIGNUM_NEGATIVE_P(bn
) && dig
<= -fixnum_min
) ||
396 (!BIGNUM_NEGATIVE_P(bn
) && dig
<= fixnum_max
);
399 cell
bignum_maybe_to_fixnum(bignum
* bn
) {
400 if (bignum_fits_fixnum_p(bn
))
401 return tag_fixnum(bignum_to_fixnum(bn
));
402 return tag
<bignum
>(bn
);
405 // cannot allocate memory
406 fixnum
factor_vm::bignum_to_fixnum_strict(bignum
* bn
) {
408 if (!bignum_fits_fixnum_p(bn
)) {
409 general_error(ERROR_OUT_OF_FIXNUM_RANGE
, tag
<bignum
>(bn
), false_object
);
411 fixnum fix
= bignum_to_fixnum(bn
);
412 FACTOR_ASSERT(fix
<= fixnum_max
&& fix
>= fixnum_min
);
416 #define DTB_WRITE_DIGIT(factor) \
418 significand *= (factor); \
419 digit = ((bignum_digit_type) significand); \
421 significand -= ((double)digit); \
424 #define inf std::numeric_limits<double>::infinity()
427 bignum
* factor_vm::double_to_bignum(double x
) {
428 if (x
== inf
|| x
== -inf
|| x
!= x
)
429 return (BIGNUM_ZERO());
431 double significand
= (frexp(x
, (&exponent
)));
433 return (BIGNUM_ZERO());
435 return (BIGNUM_ONE(x
< 0));
437 significand
= (-significand
);
439 bignum_length_type length
= (BIGNUM_BITS_TO_DIGITS(exponent
));
440 bignum
* result
= (allot_bignum(length
, (x
< 0)));
441 bignum_digit_type
* start
= (BIGNUM_START_PTR(result
));
442 bignum_digit_type
* scan
= (start
+ length
);
443 bignum_digit_type digit
;
444 int odd_bits
= (exponent
% BIGNUM_DIGIT_LENGTH
);
446 DTB_WRITE_DIGIT((fixnum
)1 << odd_bits
);
447 while (start
< scan
) {
448 if (significand
== 0) {
453 DTB_WRITE_DIGIT(BIGNUM_RADIX
);
459 #undef DTB_WRITE_DIGIT
463 int factor_vm::bignum_equal_p_unsigned(bignum
* x
, bignum
* y
) {
464 bignum_length_type length
= (BIGNUM_LENGTH(x
));
465 if (length
!= (BIGNUM_LENGTH(y
)))
468 bignum_digit_type
* scan_x
= (BIGNUM_START_PTR(x
));
469 bignum_digit_type
* scan_y
= (BIGNUM_START_PTR(y
));
470 bignum_digit_type
* end_x
= (scan_x
+ length
);
471 while (scan_x
< end_x
)
472 if ((*scan_x
++) != (*scan_y
++))
478 enum bignum_comparison
factor_vm::bignum_compare_unsigned(bignum
* x
,
480 bignum_length_type x_length
= (BIGNUM_LENGTH(x
));
481 bignum_length_type y_length
= (BIGNUM_LENGTH(y
));
482 if (x_length
< y_length
)
483 return BIGNUM_COMPARISON_LESS
;
484 if (x_length
> y_length
)
485 return BIGNUM_COMPARISON_GREATER
;
487 bignum_digit_type
* start_x
= (BIGNUM_START_PTR(x
));
488 bignum_digit_type
* scan_x
= (start_x
+ x_length
);
489 bignum_digit_type
* scan_y
= ((BIGNUM_START_PTR(y
)) + y_length
);
490 while (start_x
< scan_x
) {
491 bignum_digit_type digit_x
= (*--scan_x
);
492 bignum_digit_type digit_y
= (*--scan_y
);
493 if (digit_x
< digit_y
)
494 return BIGNUM_COMPARISON_LESS
;
495 if (digit_x
> digit_y
)
496 return BIGNUM_COMPARISON_GREATER
;
499 return BIGNUM_COMPARISON_EQUAL
;
505 bignum
* factor_vm::bignum_add_unsigned(bignum
* x_
, bignum
* y_
, int negative_p
) {
507 data_root
<bignum
> x(x_
, this);
508 data_root
<bignum
> y(y_
, this);
509 if ((BIGNUM_LENGTH(y
)) > (BIGNUM_LENGTH(x
))) {
513 bignum_length_type x_length
= (BIGNUM_LENGTH(x
));
515 bignum
* r
= (allot_bignum((x_length
+ 1), negative_p
));
517 bignum_digit_type sum
;
518 bignum_digit_type carry
= 0;
519 bignum_digit_type
* scan_x
= (BIGNUM_START_PTR(x
));
520 bignum_digit_type
* scan_r
= (BIGNUM_START_PTR(r
));
522 bignum_digit_type
* scan_y
= (BIGNUM_START_PTR(y
));
523 bignum_digit_type
* end_y
= (scan_y
+ (BIGNUM_LENGTH(y
)));
524 while (scan_y
< end_y
) {
525 sum
= ((*scan_x
++) + (*scan_y
++) + carry
);
526 if (sum
< BIGNUM_RADIX
) {
530 (*scan_r
++) = (sum
- BIGNUM_RADIX
);
536 bignum_digit_type
* end_x
= BIGNUM_START_PTR(x
) + x_length
;
538 while (scan_x
< end_x
) {
539 sum
= ((*scan_x
++) + 1);
540 if (sum
< BIGNUM_RADIX
) {
545 (*scan_r
++) = (sum
- BIGNUM_RADIX
);
547 while (scan_x
< end_x
)
548 (*scan_r
++) = (*scan_x
++);
554 return (bignum_shorten_length(r
, x_length
));
561 bignum
* factor_vm::bignum_subtract_unsigned(bignum
* x_
, bignum
* y_
) {
563 data_root
<bignum
> x(x_
, this);
564 data_root
<bignum
> y(y_
, this);
567 switch (bignum_compare_unsigned(x
.untagged(), y
.untagged())) {
568 case BIGNUM_COMPARISON_EQUAL
:
569 return (BIGNUM_ZERO());
570 case BIGNUM_COMPARISON_LESS
:
574 case BIGNUM_COMPARISON_GREATER
:
579 bignum_length_type x_length
= (BIGNUM_LENGTH(x
));
581 bignum
* r
= (allot_bignum(x_length
, negative_p
));
583 bignum_digit_type difference
;
584 bignum_digit_type borrow
= 0;
585 bignum_digit_type
* scan_x
= BIGNUM_START_PTR(x
);
586 bignum_digit_type
* scan_r
= BIGNUM_START_PTR(r
);
588 bignum_digit_type
* scan_y
= BIGNUM_START_PTR(y
);
589 bignum_digit_type
* end_y
= (scan_y
+ (BIGNUM_LENGTH(y
)));
590 while (scan_y
< end_y
) {
591 difference
= (((*scan_x
++) - (*scan_y
++)) - borrow
);
592 if (difference
< 0) {
593 (*scan_r
++) = (difference
+ BIGNUM_RADIX
);
596 (*scan_r
++) = difference
;
602 bignum_digit_type
* end_x
= BIGNUM_START_PTR(x
) + x_length
;
604 while (scan_x
< end_x
) {
605 difference
= ((*scan_x
++) - borrow
);
607 (*scan_r
++) = (difference
+ BIGNUM_RADIX
);
609 (*scan_r
++) = difference
;
614 BIGNUM_ASSERT(borrow
== 0);
615 while (scan_x
< end_x
)
616 (*scan_r
++) = (*scan_x
++);
618 return (bignum_trim(r
));
623 // Maximum value for product_low or product_high:
624 // ((R * R) + (R * (R - 2)) + (R - 1))
625 // Maximum value for carry: ((R * (R - 1)) + (R - 1))
626 // where R == BIGNUM_RADIX_ROOT
629 bignum
* factor_vm::bignum_multiply_unsigned(bignum
* x_
, bignum
* y_
,
632 data_root
<bignum
> x(x_
, this);
633 data_root
<bignum
> y(y_
, this);
635 if (BIGNUM_LENGTH(y
) > BIGNUM_LENGTH(x
)) {
639 bignum_digit_type carry
;
640 bignum_digit_type y_digit_low
;
641 bignum_digit_type y_digit_high
;
642 bignum_digit_type x_digit_low
;
643 bignum_digit_type x_digit_high
;
644 bignum_digit_type product_low
;
645 bignum_digit_type
* scan_r
;
646 bignum_digit_type
* scan_y
;
647 bignum_length_type x_length
= BIGNUM_LENGTH(x
);
648 bignum_length_type y_length
= BIGNUM_LENGTH(y
);
650 bignum
* r
= (allot_bignum_zeroed((x_length
+ y_length
), negative_p
));
652 bignum_digit_type
* scan_x
= BIGNUM_START_PTR(x
);
653 bignum_digit_type
* end_x
= (scan_x
+ x_length
);
654 bignum_digit_type
* start_y
= BIGNUM_START_PTR(y
);
655 bignum_digit_type
* end_y
= (start_y
+ y_length
);
656 bignum_digit_type
* start_r
= (BIGNUM_START_PTR(r
));
657 #define x_digit x_digit_high
658 #define y_digit y_digit_high
659 #define product_high carry
660 while (scan_x
< end_x
) {
661 x_digit
= (*scan_x
++);
662 x_digit_low
= (HD_LOW(x_digit
));
663 x_digit_high
= (HD_HIGH(x_digit
));
666 scan_r
= (start_r
++);
667 while (scan_y
< end_y
) {
668 y_digit
= (*scan_y
++);
669 y_digit_low
= (HD_LOW(y_digit
));
670 y_digit_high
= (HD_HIGH(y_digit
));
672 ((*scan_r
) + (x_digit_low
* y_digit_low
) + (HD_LOW(carry
)));
674 ((x_digit_high
* y_digit_low
) + (x_digit_low
* y_digit_high
) +
675 (HD_HIGH(product_low
)) + (HD_HIGH(carry
)));
676 (*scan_r
++) = (HD_CONS((HD_LOW(product_high
)), (HD_LOW(product_low
))));
677 carry
= ((x_digit_high
* y_digit_high
) + (HD_HIGH(product_high
)));
681 return (bignum_trim(r
));
689 bignum
* factor_vm::bignum_multiply_unsigned_small_factor(bignum
* x_
,
692 data_root
<bignum
> x(x_
, this);
694 bignum_length_type length_x
= (BIGNUM_LENGTH(x
));
696 bignum
* p
= (allot_bignum((length_x
+ 1), negative_p
));
698 bignum_destructive_copy(x
.untagged(), p
);
699 (BIGNUM_REF(p
, length_x
)) = 0;
700 bignum_destructive_scale_up(p
, y
);
701 return (bignum_trim(p
));
704 void factor_vm::bignum_destructive_add(bignum
* bn
, bignum_digit_type n
) {
705 bignum_digit_type
* scan
= (BIGNUM_START_PTR(bn
));
706 bignum_digit_type digit
;
707 digit
= ((*scan
) + n
);
708 if (digit
< BIGNUM_RADIX
) {
712 (*scan
++) = (digit
- BIGNUM_RADIX
);
714 digit
= ((*scan
) + 1);
715 if (digit
< BIGNUM_RADIX
) {
719 (*scan
++) = (digit
- BIGNUM_RADIX
);
723 void factor_vm::bignum_destructive_scale_up(bignum
* bn
,
724 bignum_digit_type factor
) {
725 bignum_digit_type carry
= 0;
726 bignum_digit_type
* scan
= (BIGNUM_START_PTR(bn
));
727 bignum_digit_type two_digits
;
728 bignum_digit_type product_low
;
729 #define product_high carry
730 bignum_digit_type
* end
= (scan
+ (BIGNUM_LENGTH(bn
)));
731 BIGNUM_ASSERT((factor
> 1) && (factor
< BIGNUM_RADIX_ROOT
));
733 two_digits
= (*scan
);
734 product_low
= ((factor
* (HD_LOW(two_digits
))) + (HD_LOW(carry
)));
735 product_high
= ((factor
* (HD_HIGH(two_digits
))) + (HD_HIGH(product_low
)) +
737 (*scan
++) = (HD_CONS((HD_LOW(product_high
)), (HD_LOW(product_low
))));
738 carry
= (HD_HIGH(product_high
));
740 // A carry here would be an overflow, i.e. it would not fit.
741 // Hopefully the callers allocate enough space that this will
743 BIGNUM_ASSERT(carry
== 0);
750 // For help understanding this algorithm, see:
751 // Knuth, Donald E., "The Art of Computer Programming",
752 // volume 2, "Seminumerical Algorithms"
753 // section 4.3.1, "Multiple-Precision Arithmetic".
756 void factor_vm::bignum_divide_unsigned_large_denominator(
757 bignum
* numerator_
, bignum
* denominator_
,
758 bignum
** quotient
, bignum
** remainder
,
759 int q_negative_p
, int r_negative_p
) {
761 data_root
<bignum
> numerator(numerator_
, this);
762 data_root
<bignum
> denominator(denominator_
, this);
764 bignum_length_type length_n
= BIGNUM_LENGTH(numerator
) + 1;
765 bignum_length_type length_d
= BIGNUM_LENGTH(denominator
);
767 data_root
<bignum
> u(allot_bignum(length_n
, r_negative_p
), this);
770 BIGNUM_ASSERT(length_d
> 1);
772 bignum_digit_type v1
= BIGNUM_REF(denominator
.untagged(), length_d
- 1);
773 while (v1
< (BIGNUM_RADIX
/ 2)) {
779 if (quotient
!= NULL
) {
780 bignum
*q_
= allot_bignum(length_n
- length_d
, q_negative_p
);
781 data_root
<bignum
> q(q_
, this);
784 bignum_destructive_copy(numerator
.untagged(), u
.untagged());
785 (BIGNUM_REF(u
.untagged(), (length_n
- 1))) = 0;
786 bignum_divide_unsigned_normalized(u
.untagged(),
787 denominator
.untagged(),
790 bignum
* v
= allot_bignum(length_d
, 0);
791 bignum_destructive_normalization(numerator
.untagged(),
794 bignum_destructive_normalization(denominator
.untagged(), v
, shift
);
795 bignum_divide_unsigned_normalized(u
.untagged(), v
, q
.untagged());
796 if (remainder
!= NULL
)
797 bignum_destructive_unnormalization(u
.untagged(), shift
);
800 q
.set_untagged(bignum_trim(q
.untagged()));
801 *quotient
= q
.untagged();
805 bignum_destructive_copy(numerator
.untagged(), u
.untagged());
806 (BIGNUM_REF(u
.untagged(), (length_n
- 1))) = 0;
807 bignum_divide_unsigned_normalized(u
.untagged(),
808 denominator
.untagged(),
811 bignum
* v
= allot_bignum(length_d
, 0);
812 bignum_destructive_normalization(numerator
.untagged(),
815 bignum_destructive_normalization(denominator
.untagged(),
818 bignum_divide_unsigned_normalized(u
.untagged(), v
, NULL
);
819 if (remainder
!= NULL
)
820 bignum_destructive_unnormalization(u
.untagged(), shift
);
824 u
.set_untagged(bignum_trim(u
.untagged()));
825 if (remainder
!= NULL
)
826 *remainder
= u
.untagged();
829 void factor_vm::bignum_divide_unsigned_normalized(bignum
* u
, bignum
* v
,
831 bignum_length_type u_length
= (BIGNUM_LENGTH(u
));
832 bignum_length_type v_length
= (BIGNUM_LENGTH(v
));
833 bignum_digit_type
* u_start
= (BIGNUM_START_PTR(u
));
834 bignum_digit_type
* u_scan
= (u_start
+ u_length
);
835 bignum_digit_type
* u_scan_limit
= (u_start
+ v_length
);
836 bignum_digit_type
* u_scan_start
= (u_scan
- v_length
);
837 bignum_digit_type
* v_start
= (BIGNUM_START_PTR(v
));
838 bignum_digit_type
* v_end
= (v_start
+ v_length
);
839 bignum_digit_type
* q_scan
= NULL
;
840 bignum_digit_type v1
= (v_end
[-1]);
841 bignum_digit_type v2
= (v_end
[-2]);
842 bignum_digit_type ph
; // high half of double-digit product
843 bignum_digit_type pl
; // low half of double-digit product
844 bignum_digit_type guess
;
845 bignum_digit_type gh
; // high half-digit of guess
846 bignum_digit_type ch
; // high half of double-digit comparand
847 bignum_digit_type v2l
= (HD_LOW(v2
));
848 bignum_digit_type v2h
= (HD_HIGH(v2
));
849 bignum_digit_type cl
; // low half of double-digit comparand
850 #define gl ph // low half-digit of guess
853 bignum_digit_type gm
; // memory loc for reference parameter
854 if (q
!= BIGNUM_OUT_OF_BAND
)
855 q_scan
= ((BIGNUM_START_PTR(q
)) + (BIGNUM_LENGTH(q
)));
856 while (u_scan_limit
< u_scan
) {
860 // (((((uj * BIGNUM_RADIX) + uj1) % v1) * BIGNUM_RADIX) + uj2);
861 // guess = (((uj * BIGNUM_RADIX) + uj1) / v1);
863 ch
= (bignum_digit_divide(uj
, (u_scan
[-1]), v1
, (&gm
)));
867 ch
= ((u_scan
[-1]) + v1
);
868 guess
= (BIGNUM_RADIX
- 1);
871 // product = (guess * v2);
872 gl
= (HD_LOW(guess
));
873 gh
= (HD_HIGH(guess
));
875 ph
= ((v2l
* gh
) + (v2h
* gl
) + (HD_HIGH(pl
)));
876 pl
= (HD_CONS((HD_LOW(ph
)), (HD_LOW(pl
))));
877 ph
= ((v2h
* gh
) + (HD_HIGH(ph
)));
878 // if (comparand >= product)
879 if ((ch
> ph
) || ((ch
== ph
) && (cl
>= pl
)))
882 // comparand += (v1 << BIGNUM_DIGIT_LENGTH)
884 // if (comparand >= (BIGNUM_RADIX * BIGNUM_RADIX))
885 if (ch
>= BIGNUM_RADIX
)
888 qj
= (bignum_divide_subtract(v_start
, v_end
, guess
, (--u_scan_start
)));
889 if (q
!= BIGNUM_OUT_OF_BAND
)
898 bignum_digit_type
factor_vm::bignum_divide_subtract(
899 bignum_digit_type
* v_start
, bignum_digit_type
* v_end
,
900 bignum_digit_type guess
, bignum_digit_type
* u_start
) {
901 bignum_digit_type
* v_scan
= v_start
;
902 bignum_digit_type
* u_scan
= u_start
;
903 bignum_digit_type carry
= 0;
907 bignum_digit_type gl
= (HD_LOW(guess
));
908 bignum_digit_type gh
= (HD_HIGH(guess
));
910 bignum_digit_type pl
;
911 bignum_digit_type vl
;
915 while (v_scan
< v_end
) {
919 pl
= ((vl
* gl
) + (HD_LOW(carry
)));
920 ph
= ((vl
* gh
) + (vh
* gl
) + (HD_HIGH(pl
)) + (HD_HIGH(carry
)));
921 diff
= ((*u_scan
) - (HD_CONS((HD_LOW(ph
)), (HD_LOW(pl
)))));
923 (*u_scan
++) = (diff
+ BIGNUM_RADIX
);
924 carry
= ((vh
* gh
) + (HD_HIGH(ph
)) + 1);
927 carry
= ((vh
* gh
) + (HD_HIGH(ph
)));
932 diff
= ((*u_scan
) - carry
);
934 (*u_scan
) = (diff
+ BIGNUM_RADIX
);
943 // Subtraction generated carry, implying guess is one too large.
944 // Add v back in to bring it back down.
948 while (v_scan
< v_end
) {
949 bignum_digit_type sum
= ((*v_scan
++) + (*u_scan
) + carry
);
950 if (sum
< BIGNUM_RADIX
) {
954 (*u_scan
++) = (sum
- BIGNUM_RADIX
);
959 bignum_digit_type sum
= ((*u_scan
) + carry
);
960 (*u_scan
) = ((sum
< BIGNUM_RADIX
) ? sum
: (sum
- BIGNUM_RADIX
));
966 void factor_vm::bignum_divide_unsigned_medium_denominator(
967 bignum
* numerator_
, bignum_digit_type denominator
, bignum
** quotient
,
968 bignum
** remainder
, int q_negative_p
, int r_negative_p
) {
970 data_root
<bignum
> numerator(numerator_
, this);
972 bignum_length_type length_n
= (BIGNUM_LENGTH(numerator
));
975 // Because `bignum_digit_divide' requires a normalized denominator.
976 while (denominator
< (BIGNUM_RADIX
/ 2)) {
981 bignum_length_type length_q
= (shift
== 0) ? length_n
: length_n
+ 1;
982 data_root
<bignum
> q(allot_bignum(length_q
, q_negative_p
), this);
984 bignum_destructive_copy(numerator
.untagged(), q
.untagged());
986 bignum_destructive_normalization(numerator
.untagged(), q
.untagged(), shift
);
989 bignum_digit_type r
= 0;
990 bignum_digit_type
* start
= (BIGNUM_START_PTR(q
));
991 bignum_digit_type
* scan
= (start
+ length_q
);
992 bignum_digit_type qj
;
994 while (start
< scan
) {
995 r
= (bignum_digit_divide(r
, (*--scan
), denominator
, (&qj
)));
999 q
.set_untagged(bignum_trim(q
.untagged()));
1001 if (remainder
!= ((bignum
**)0)) {
1005 (*remainder
) = (bignum_digit_to_bignum(r
, r_negative_p
));
1008 if (quotient
!= ((bignum
**)0))
1009 (*quotient
) = q
.untagged();
1014 void factor_vm::bignum_destructive_normalization(bignum
* source
, bignum
* target
,
1016 bignum_digit_type digit
;
1017 bignum_digit_type
* scan_source
= (BIGNUM_START_PTR(source
));
1018 bignum_digit_type carry
= 0;
1019 bignum_digit_type
* scan_target
= (BIGNUM_START_PTR(target
));
1020 bignum_digit_type
* end_source
= (scan_source
+ (BIGNUM_LENGTH(source
)));
1021 bignum_digit_type
* end_target
= (scan_target
+ (BIGNUM_LENGTH(target
)));
1022 int shift_right
= (BIGNUM_DIGIT_LENGTH
- shift_left
);
1023 bignum_digit_type mask
= (((cell
)1 << shift_right
) - 1);
1024 while (scan_source
< end_source
) {
1025 digit
= (*scan_source
++);
1026 (*scan_target
++) = (((digit
& mask
) << shift_left
) | carry
);
1027 carry
= (digit
>> shift_right
);
1029 if (scan_target
< end_target
)
1030 (*scan_target
) = carry
;
1032 BIGNUM_ASSERT(carry
== 0);
1036 void factor_vm::bignum_destructive_unnormalization(bignum
* bn
,
1038 bignum_digit_type
* start
= (BIGNUM_START_PTR(bn
));
1039 bignum_digit_type
* scan
= (start
+ (BIGNUM_LENGTH(bn
)));
1040 bignum_digit_type digit
;
1041 bignum_digit_type carry
= 0;
1042 int shift_left
= (BIGNUM_DIGIT_LENGTH
- shift_right
);
1043 bignum_digit_type mask
= (((fixnum
)1 << shift_right
) - 1);
1044 while (start
< scan
) {
1046 (*scan
) = ((digit
>> shift_right
) | carry
);
1047 carry
= ((digit
& mask
) << shift_left
);
1049 BIGNUM_ASSERT(carry
== 0);
1053 // This is a reduced version of the division algorithm, applied to the
1054 // case of dividing two bignum digits by one bignum digit. It is
1055 // assumed that the numerator, denominator are normalized.
1057 #define BDD_STEP(qn, j) \
1061 uj_uj1 = (HD_CONS(uj, (u[j + 1]))); \
1062 guess = (uj_uj1 / v1); \
1063 comparand = (HD_CONS((uj_uj1 % v1), (u[j + 2]))); \
1065 guess = (BIGNUM_RADIX_ROOT - 1); \
1066 comparand = (HD_CONS(((u[j + 1]) + v1), (u[j + 2]))); \
1068 while ((guess * v2) > comparand) { \
1070 comparand += (v1 << BIGNUM_HALF_DIGIT_LENGTH); \
1071 if (comparand >= BIGNUM_RADIX) \
1074 qn = (bignum_digit_divide_subtract(v1, v2, guess, (&u[j]))); \
1077 bignum_digit_type
factor_vm::bignum_digit_divide(
1078 bignum_digit_type uh
, bignum_digit_type ul
, bignum_digit_type v
,
1079 bignum_digit_type
* q
) // return value
1081 bignum_digit_type guess
;
1082 bignum_digit_type comparand
;
1083 bignum_digit_type v1
= (HD_HIGH(v
));
1084 bignum_digit_type v2
= (HD_LOW(v
));
1085 bignum_digit_type uj
;
1086 bignum_digit_type uj_uj1
;
1087 bignum_digit_type q1
;
1088 bignum_digit_type q2
;
1089 bignum_digit_type u
[4];
1094 } else if (ul
== v
) {
1099 (u
[0]) = (HD_HIGH(uh
));
1100 (u
[1]) = (HD_LOW(uh
));
1101 (u
[2]) = (HD_HIGH(ul
));
1102 (u
[3]) = (HD_LOW(ul
));
1107 (*q
) = (HD_CONS(q1
, q2
));
1108 return (HD_CONS((u
[2]), (u
[3])));
1113 #define BDDS_MULSUB(vn, un, carry_in) \
1115 product = ((vn * guess) + carry_in); \
1116 diff = (un - (HD_LOW(product))); \
1118 un = (diff + BIGNUM_RADIX_ROOT); \
1119 carry = ((HD_HIGH(product)) + 1); \
1122 carry = (HD_HIGH(product)); \
1126 #define BDDS_ADD(vn, un, carry_in) \
1128 sum = (vn + un + carry_in); \
1129 if (sum < BIGNUM_RADIX_ROOT) { \
1133 un = (sum - BIGNUM_RADIX_ROOT); \
1138 bignum_digit_type
factor_vm::bignum_digit_divide_subtract(
1139 bignum_digit_type v1
, bignum_digit_type v2
, bignum_digit_type guess
,
1140 bignum_digit_type
* u
) {
1142 bignum_digit_type product
;
1143 bignum_digit_type diff
;
1144 bignum_digit_type carry
;
1145 BDDS_MULSUB(v2
, (u
[2]), 0);
1146 BDDS_MULSUB(v1
, (u
[1]), carry
);
1149 diff
= ((u
[0]) - carry
);
1151 (u
[0]) = (diff
+ BIGNUM_RADIX
);
1158 bignum_digit_type sum
;
1159 bignum_digit_type carry
;
1160 BDDS_ADD(v2
, (u
[2]), 0);
1161 BDDS_ADD(v1
, (u
[1]), carry
);
1172 void factor_vm::bignum_divide_unsigned_small_denominator(
1173 bignum
* numerator_
, bignum_digit_type denominator
, bignum
** quotient
,
1174 bignum
** remainder
, int q_negative_p
, int r_negative_p
) {
1175 data_root
<bignum
> numerator(numerator_
, this);
1177 bignum
* q_
= bignum_new_sign(numerator
.untagged(), q_negative_p
);
1178 data_root
<bignum
> q(q_
, this);
1180 bignum_digit_type r
= bignum_destructive_scale_down(q
.untagged(), denominator
);
1182 q
.set_untagged(bignum_trim(q
.untagged()));
1184 if (remainder
!= ((bignum
**)0))
1185 (*remainder
) = bignum_digit_to_bignum(r
, r_negative_p
);
1187 (*quotient
) = q
.untagged();
1192 // Given (denominator > 1), it is fairly easy to show that
1193 // (quotient_high < BIGNUM_RADIX_ROOT), after which it is easy to see
1194 // that all digits are < BIGNUM_RADIX.
1196 bignum_digit_type
factor_vm::bignum_destructive_scale_down(
1197 bignum
* bn
, bignum_digit_type denominator
) {
1198 bignum_digit_type numerator
;
1199 bignum_digit_type remainder
= 0;
1200 bignum_digit_type two_digits
;
1201 #define quotient_high remainder
1202 bignum_digit_type
* start
= (BIGNUM_START_PTR(bn
));
1203 bignum_digit_type
* scan
= (start
+ (BIGNUM_LENGTH(bn
)));
1204 BIGNUM_ASSERT((denominator
> 1) && (denominator
< BIGNUM_RADIX_ROOT
));
1205 while (start
< scan
) {
1206 two_digits
= (*--scan
);
1207 numerator
= (HD_CONS(remainder
, (HD_HIGH(two_digits
))));
1208 quotient_high
= (numerator
/ denominator
);
1209 numerator
= (HD_CONS((numerator
% denominator
), (HD_LOW(two_digits
))));
1210 (*scan
) = (HD_CONS(quotient_high
, (numerator
/ denominator
)));
1211 remainder
= (numerator
% denominator
);
1214 #undef quotient_high
1218 bignum
* factor_vm::bignum_remainder_unsigned_small_denominator(
1219 bignum
* n
, bignum_digit_type d
, int negative_p
) {
1220 bignum_digit_type two_digits
;
1221 bignum_digit_type
* start
= (BIGNUM_START_PTR(n
));
1222 bignum_digit_type
* scan
= (start
+ (BIGNUM_LENGTH(n
)));
1223 bignum_digit_type r
= 0;
1224 BIGNUM_ASSERT((d
> 1) && (d
< BIGNUM_RADIX_ROOT
));
1225 while (start
< scan
) {
1226 two_digits
= (*--scan
);
1227 r
= ((HD_CONS(((HD_CONS(r
, (HD_HIGH(two_digits
)))) % d
),
1228 (HD_LOW(two_digits
)))) %
1231 return (bignum_digit_to_bignum(r
, negative_p
));
1235 bignum
* factor_vm::bignum_digit_to_bignum(bignum_digit_type digit
,
1238 return (BIGNUM_ZERO());
1240 bignum
* result
= (allot_bignum(1, negative_p
));
1241 (BIGNUM_REF(result
, 0)) = digit
;
1247 bignum
* factor_vm::allot_bignum(bignum_length_type length
, int negative_p
) {
1248 BIGNUM_ASSERT((length
>= 0) || (length
< BIGNUM_RADIX
));
1249 bignum
* result
= allot_uninitialized_array
<bignum
>(length
+ 1);
1250 BIGNUM_SET_NEGATIVE_P(result
, negative_p
);
1255 bignum
* factor_vm::allot_bignum_zeroed(bignum_length_type length
,
1257 bignum
* result
= allot_bignum(length
, negative_p
);
1258 bignum_digit_type
* scan
= (BIGNUM_START_PTR(result
));
1259 bignum_digit_type
* end
= (scan
+ length
);
1266 bignum
* factor_vm::bignum_shorten_length(bignum
* bn
,
1267 bignum_length_type length
) {
1268 bignum_length_type current_length
= (BIGNUM_LENGTH(bn
));
1269 BIGNUM_ASSERT((length
>= 0) || (length
<= current_length
));
1270 if (length
< current_length
) {
1271 bn
= reallot_array(bn
, length
+ 1);
1272 BIGNUM_SET_NEGATIVE_P(bn
, (length
!= 0) && (BIGNUM_NEGATIVE_P(bn
)));
1278 bignum
* factor_vm::bignum_trim(bignum
* bn
) {
1279 bignum_digit_type
* start
= (BIGNUM_START_PTR(bn
));
1280 bignum_digit_type
* end
= (start
+ (BIGNUM_LENGTH(bn
)));
1281 bignum_digit_type
* scan
= end
;
1282 while ((start
<= scan
) && ((*--scan
) == 0))
1286 bignum_length_type length
= (scan
- start
);
1287 bn
= reallot_array(bn
, length
+ 1);
1288 BIGNUM_SET_NEGATIVE_P(bn
, (length
!= 0) && (BIGNUM_NEGATIVE_P(bn
)));
1296 bignum
* factor_vm::bignum_new_sign(bignum
* x_
, int negative_p
) {
1297 data_root
<bignum
> x(x_
, this);
1298 bignum
* result
= allot_bignum(BIGNUM_LENGTH(x
), negative_p
);
1299 bignum_destructive_copy(x
.untagged(), result
);
1304 bignum
* factor_vm::bignum_maybe_new_sign(bignum
* x_
, int negative_p
) {
1305 if ((BIGNUM_NEGATIVE_P(x_
)) ? negative_p
: (!negative_p
))
1308 return bignum_new_sign(x_
, negative_p
);
1312 void factor_vm::bignum_destructive_copy(bignum
* source
, bignum
* target
) {
1313 bignum_digit_type
* scan_source
= (BIGNUM_START_PTR(source
));
1314 bignum_digit_type
* end_source
= (scan_source
+ (BIGNUM_LENGTH(source
)));
1315 bignum_digit_type
* scan_target
= (BIGNUM_START_PTR(target
));
1316 while (scan_source
< end_source
)
1317 (*scan_target
++) = (*scan_source
++);
1321 // * Added bitwise operations (and oddp).
1324 bignum
* factor_vm::bignum_bitwise_not(bignum
* x_
) {
1327 bignum_length_type size
= BIGNUM_LENGTH(x_
);
1328 int is_negative
= BIGNUM_NEGATIVE_P(x_
);
1329 data_root
<bignum
> x(x_
, this);
1330 data_root
<bignum
> y(allot_bignum(size
, is_negative
? 0 : 1), this);
1332 bignum_digit_type
* scan_x
= BIGNUM_START_PTR(x
);
1333 bignum_digit_type
* end_x
= scan_x
+ size
;
1334 bignum_digit_type
* scan_y
= BIGNUM_START_PTR(y
);
1337 while (scan_x
< end_x
) {
1339 *scan_y
++ = BIGNUM_RADIX
- 1;
1342 *scan_y
++ = *scan_x
++ - 1;
1348 while (scan_x
< end_x
) {
1349 if (*scan_x
== (BIGNUM_RADIX
- 1)) {
1353 *scan_y
++ = *scan_x
++ + 1;
1360 while (scan_x
< end_x
) {
1361 *scan_y
++ = *scan_x
++;
1365 bignum
* ret
= allot_bignum(size
+ 1, BIGNUM_NEGATIVE_P(y
));
1366 bignum_destructive_copy(y
.untagged(), ret
);
1367 bignum_digit_type
* ret_start
= BIGNUM_START_PTR(ret
);
1368 *(ret_start
+ size
) = 1;
1371 return bignum_trim(y
.untagged());
1376 bignum
* factor_vm::bignum_arithmetic_shift(bignum
* arg1
, fixnum n
) {
1377 if (BIGNUM_NEGATIVE_P(arg1
) && n
< 0)
1378 return bignum_bitwise_not(
1379 bignum_magnitude_ash(bignum_bitwise_not(arg1
), n
));
1381 return bignum_magnitude_ash(arg1
, n
);
1389 bignum
* factor_vm::bignum_bitwise_and(bignum
* arg1
, bignum
* arg2
) {
1390 return ((BIGNUM_NEGATIVE_P(arg1
)) ? (BIGNUM_NEGATIVE_P(arg2
))
1391 ? bignum_negneg_bitwise_op(AND_OP
, arg1
, arg2
)
1392 : bignum_posneg_bitwise_op(AND_OP
, arg2
, arg1
)
1393 : (BIGNUM_NEGATIVE_P(arg2
))
1394 ? bignum_posneg_bitwise_op(AND_OP
, arg1
, arg2
)
1395 : bignum_pospos_bitwise_op(AND_OP
, arg1
, arg2
));
1399 bignum
* factor_vm::bignum_bitwise_ior(bignum
* arg1
, bignum
* arg2
) {
1400 return ((BIGNUM_NEGATIVE_P(arg1
)) ? (BIGNUM_NEGATIVE_P(arg2
))
1401 ? bignum_negneg_bitwise_op(IOR_OP
, arg1
, arg2
)
1402 : bignum_posneg_bitwise_op(IOR_OP
, arg2
, arg1
)
1403 : (BIGNUM_NEGATIVE_P(arg2
))
1404 ? bignum_posneg_bitwise_op(IOR_OP
, arg1
, arg2
)
1405 : bignum_pospos_bitwise_op(IOR_OP
, arg1
, arg2
));
1409 bignum
* factor_vm::bignum_bitwise_xor(bignum
* arg1
, bignum
* arg2
) {
1410 return ((BIGNUM_NEGATIVE_P(arg1
)) ? (BIGNUM_NEGATIVE_P(arg2
))
1411 ? bignum_negneg_bitwise_op(XOR_OP
, arg1
, arg2
)
1412 : bignum_posneg_bitwise_op(XOR_OP
, arg2
, arg1
)
1413 : (BIGNUM_NEGATIVE_P(arg2
))
1414 ? bignum_posneg_bitwise_op(XOR_OP
, arg1
, arg2
)
1415 : bignum_pospos_bitwise_op(XOR_OP
, arg1
, arg2
));
1419 // ash for the magnitude
1420 // assume arg1 is a big number, n is a long
1421 bignum
* factor_vm::bignum_magnitude_ash(bignum
* arg1_
, fixnum n
) {
1423 data_root
<bignum
> arg1(arg1_
, this);
1425 bignum
* result
= NULL
;
1426 bignum_digit_type
* scan1
;
1427 bignum_digit_type
* scanr
;
1428 bignum_digit_type
* end
;
1430 fixnum digit_offset
, bit_offset
;
1432 if (BIGNUM_ZERO_P(arg1
))
1433 return arg1
.untagged();
1436 digit_offset
= n
/ BIGNUM_DIGIT_LENGTH
;
1437 bit_offset
= n
% BIGNUM_DIGIT_LENGTH
;
1439 result
= allot_bignum_zeroed(BIGNUM_LENGTH(arg1
) + digit_offset
+ 1,
1440 BIGNUM_NEGATIVE_P(arg1
));
1442 scanr
= BIGNUM_START_PTR(result
) + digit_offset
;
1443 scan1
= BIGNUM_START_PTR(arg1
);
1444 end
= scan1
+ BIGNUM_LENGTH(arg1
);
1446 while (scan1
< end
) {
1447 *scanr
= *scanr
| (*scan1
& BIGNUM_DIGIT_MASK
) << bit_offset
;
1448 *scanr
= *scanr
& BIGNUM_DIGIT_MASK
;
1450 *scanr
= *scan1
++ >> (BIGNUM_DIGIT_LENGTH
- bit_offset
);
1451 *scanr
= *scanr
& BIGNUM_DIGIT_MASK
;
1453 } else if (n
< 0 && (-n
>= (BIGNUM_LENGTH(arg1
) * (bignum_length_type
)
1454 BIGNUM_DIGIT_LENGTH
))) {
1455 result
= BIGNUM_ZERO();
1457 digit_offset
= -n
/ BIGNUM_DIGIT_LENGTH
;
1458 bit_offset
= -n
% BIGNUM_DIGIT_LENGTH
;
1460 result
= allot_bignum_zeroed(BIGNUM_LENGTH(arg1
) - digit_offset
,
1461 BIGNUM_NEGATIVE_P(arg1
));
1463 scanr
= BIGNUM_START_PTR(result
);
1464 scan1
= BIGNUM_START_PTR(arg1
) + digit_offset
;
1465 end
= scanr
+ BIGNUM_LENGTH(result
) - 1;
1467 while (scanr
< end
) {
1468 *scanr
= (*scan1
++ & BIGNUM_DIGIT_MASK
) >> bit_offset
;
1469 *scanr
= (*scanr
| *scan1
<< (BIGNUM_DIGIT_LENGTH
- bit_offset
)) &
1473 *scanr
= (*scan1
++ & BIGNUM_DIGIT_MASK
) >> bit_offset
;
1474 } else if (n
== 0) {
1475 result
= arg1
.untagged();
1478 return bignum_trim(result
);
1482 bignum
* factor_vm::bignum_pospos_bitwise_op(int op
, bignum
* arg1_
,
1484 data_root
<bignum
> arg1(arg1_
, this);
1485 data_root
<bignum
> arg2(arg2_
, this);
1487 bignum_length_type max_length
;
1489 bignum_digit_type
* scan1
, *end1
, digit1
;
1490 bignum_digit_type
* scan2
, *end2
, digit2
;
1491 bignum_digit_type
* scanr
, *endr
;
1494 (BIGNUM_LENGTH(arg1
) > BIGNUM_LENGTH(arg2
)) ? BIGNUM_LENGTH(arg1
)
1495 : BIGNUM_LENGTH(arg2
);
1497 bignum
* result
= allot_bignum(max_length
, 0);
1499 scanr
= BIGNUM_START_PTR(result
);
1500 scan1
= BIGNUM_START_PTR(arg1
);
1501 scan2
= BIGNUM_START_PTR(arg2
);
1502 endr
= scanr
+ max_length
;
1503 end1
= scan1
+ BIGNUM_LENGTH(arg1
);
1504 end2
= scan2
+ BIGNUM_LENGTH(arg2
);
1506 while (scanr
< endr
) {
1507 digit1
= (scan1
< end1
) ? *scan1
++ : 0;
1508 digit2
= (scan2
< end2
) ? *scan2
++ : 0;
1510 (op
== AND_OP
) ? digit1
& digit2
: (op
== IOR_OP
) ? digit1
| digit2
1513 return bignum_trim(result
);
1517 bignum
* factor_vm::bignum_posneg_bitwise_op(int op
, bignum
* arg1_
,
1519 data_root
<bignum
> arg1(arg1_
, this);
1520 data_root
<bignum
> arg2(arg2_
, this);
1522 bignum_length_type max_length
;
1524 bignum_digit_type
* scan1
, *end1
, digit1
;
1525 bignum_digit_type
* scan2
, *end2
, digit2
, carry2
;
1526 bignum_digit_type
* scanr
, *endr
;
1528 char neg_p
= op
== IOR_OP
|| op
== XOR_OP
;
1531 (BIGNUM_LENGTH(arg1
) > BIGNUM_LENGTH(arg2
) + 1) ? BIGNUM_LENGTH(arg1
)
1532 : BIGNUM_LENGTH(arg2
) + 1;
1534 bignum
* result
= allot_bignum(max_length
, neg_p
);
1536 scanr
= BIGNUM_START_PTR(result
);
1537 scan1
= BIGNUM_START_PTR(arg1
);
1538 scan2
= BIGNUM_START_PTR(arg2
);
1539 endr
= scanr
+ max_length
;
1540 end1
= scan1
+ BIGNUM_LENGTH(arg1
);
1541 end2
= scan2
+ BIGNUM_LENGTH(arg2
);
1545 while (scanr
< endr
) {
1546 digit1
= (scan1
< end1
) ? *scan1
++ : 0;
1547 digit2
= (~((scan2
< end2
) ? *scan2
++ : 0) & BIGNUM_DIGIT_MASK
) + carry2
;
1549 if (digit2
< BIGNUM_RADIX
)
1552 digit2
= (digit2
- BIGNUM_RADIX
);
1557 (op
== AND_OP
) ? digit1
& digit2
: (op
== IOR_OP
) ? digit1
| digit2
1562 bignum_negate_magnitude(result
);
1564 return bignum_trim(result
);
1568 bignum
* factor_vm::bignum_negneg_bitwise_op(int op
, bignum
* arg1_
,
1570 data_root
<bignum
> arg1(arg1_
, this);
1571 data_root
<bignum
> arg2(arg2_
, this);
1573 bignum_length_type max_length
;
1575 bignum_digit_type
* scan1
, *end1
, digit1
, carry1
;
1576 bignum_digit_type
* scan2
, *end2
, digit2
, carry2
;
1577 bignum_digit_type
* scanr
, *endr
;
1579 char neg_p
= op
== AND_OP
|| op
== IOR_OP
;
1582 (BIGNUM_LENGTH(arg1
) > BIGNUM_LENGTH(arg2
)) ? BIGNUM_LENGTH(arg1
) + 1
1583 : BIGNUM_LENGTH(arg2
) + 1;
1585 bignum
* result
= allot_bignum(max_length
, neg_p
);
1587 scanr
= BIGNUM_START_PTR(result
);
1588 scan1
= BIGNUM_START_PTR(arg1
);
1589 scan2
= BIGNUM_START_PTR(arg2
);
1590 endr
= scanr
+ max_length
;
1591 end1
= scan1
+ BIGNUM_LENGTH(arg1
);
1592 end2
= scan2
+ BIGNUM_LENGTH(arg2
);
1597 while (scanr
< endr
) {
1598 digit1
= (~((scan1
< end1
) ? *scan1
++ : 0) & BIGNUM_DIGIT_MASK
) + carry1
;
1599 digit2
= (~((scan2
< end2
) ? *scan2
++ : 0) & BIGNUM_DIGIT_MASK
) + carry2
;
1601 if (digit1
< BIGNUM_RADIX
)
1604 digit1
= (digit1
- BIGNUM_RADIX
);
1608 if (digit2
< BIGNUM_RADIX
)
1611 digit2
= (digit2
- BIGNUM_RADIX
);
1616 (op
== AND_OP
) ? digit1
& digit2
: (op
== IOR_OP
) ? digit1
| digit2
1621 bignum_negate_magnitude(result
);
1623 return bignum_trim(result
);
1626 void factor_vm::bignum_negate_magnitude(bignum
* arg
) {
1627 bignum_digit_type
* scan
;
1628 bignum_digit_type
* end
;
1629 bignum_digit_type digit
;
1630 bignum_digit_type carry
;
1632 scan
= BIGNUM_START_PTR(arg
);
1633 end
= scan
+ BIGNUM_LENGTH(arg
);
1637 while (scan
< end
) {
1638 digit
= (~ * scan
& BIGNUM_DIGIT_MASK
) + carry
;
1640 if (digit
< BIGNUM_RADIX
)
1643 digit
= (digit
- BIGNUM_RADIX
);
1652 bignum
* factor_vm::bignum_integer_length(bignum
* x_
) {
1653 data_root
<bignum
> x(x_
, this);
1654 bignum_length_type index
= ((BIGNUM_LENGTH(x
)) - 1);
1655 bignum_digit_type digit
= (BIGNUM_REF(x
, index
));
1656 bignum_digit_type carry
= 0;
1664 if (index
< BIGNUM_RADIX_ROOT
) {
1665 result
= allot_bignum(1, 0);
1666 (BIGNUM_REF(result
, 0)) = (index
* BIGNUM_DIGIT_LENGTH
) + carry
;
1668 result
= allot_bignum(2, 0);
1669 (BIGNUM_REF(result
, 0)) = index
;
1670 (BIGNUM_REF(result
, 1)) = 0;
1671 bignum_destructive_scale_up(result
, BIGNUM_DIGIT_LENGTH
);
1672 bignum_destructive_add(result
, carry
);
1674 return (bignum_trim(result
));
1678 int factor_vm::bignum_logbitp(int shift
, bignum
* arg
) {
1679 return ((BIGNUM_NEGATIVE_P(arg
))
1680 ? !bignum_unsigned_logbitp(shift
, bignum_bitwise_not(arg
))
1681 : bignum_unsigned_logbitp(shift
, arg
));
1684 int factor_vm::bignum_unsigned_logbitp(int shift
, bignum
* bn
) {
1685 bignum_length_type len
= (BIGNUM_LENGTH(bn
));
1686 int index
= shift
/ BIGNUM_DIGIT_LENGTH
;
1689 bignum_digit_type digit
= (BIGNUM_REF(bn
, index
));
1690 int p
= shift
% BIGNUM_DIGIT_LENGTH
;
1691 bignum_digit_type mask
= ((fixnum
)1) << p
;
1692 return (digit
& mask
) ? 1 : 0;
1696 // Allocates memory.
1697 bignum
* factor_vm::bignum_gcd(bignum
* a_
, bignum
* b_
) {
1699 data_root
<bignum
> a(a_
, this);
1700 data_root
<bignum
> b(b_
, this);
1702 // Copies of a and b with that are both positive.
1703 data_root
<bignum
> ac(bignum_maybe_new_sign(a
.untagged(), 0), this);
1704 data_root
<bignum
> bc(bignum_maybe_new_sign(b
.untagged(), 0), this);
1706 if (bignum_compare(ac
.untagged(), bc
.untagged()) == BIGNUM_COMPARISON_LESS
) {
1710 while (BIGNUM_LENGTH(bc
) != 0) {
1711 data_root
<bignum
> d(bignum_remainder(ac
.untagged(), bc
.untagged()), this);
1712 if (d
.untagged() == BIGNUM_OUT_OF_BAND
) {
1713 return d
.untagged();
1718 return ac
.untagged();
1722 bignum
* factor_vm::bignum_gcd(bignum
* a_
, bignum
* b_
) {
1723 data_root
<bignum
> a(a_
, this);
1724 data_root
<bignum
> b(b_
, this);
1725 bignum_twodigit_type x
, y
, q
, s
, t
, A
, B
, C
, D
;
1727 bignum_length_type size_a
, size_b
, size_c
;
1728 bignum_digit_type
* scan_a
, *scan_b
, *scan_c
, *scan_d
;
1729 bignum_digit_type
* a_end
, *b_end
, *c_end
;
1731 // clone the bignums so we can modify them in-place
1732 size_a
= BIGNUM_LENGTH(a
);
1733 data_root
<bignum
> c(allot_bignum(size_a
, 0), this);
1734 // c = allot_bignum(size_a, 0);
1735 scan_a
= BIGNUM_START_PTR(a
);
1736 a_end
= scan_a
+ size_a
;
1737 scan_c
= BIGNUM_START_PTR(c
);
1738 while (scan_a
< a_end
)
1739 (*scan_c
++) = (*scan_a
++);
1741 size_b
= BIGNUM_LENGTH(b
);
1742 data_root
<bignum
> d(allot_bignum(size_b
, 0), this);
1743 scan_b
= BIGNUM_START_PTR(b
);
1744 b_end
= scan_b
+ size_b
;
1745 scan_d
= BIGNUM_START_PTR(d
);
1746 while (scan_b
< b_end
)
1747 (*scan_d
++) = (*scan_b
++);
1750 // Initial reduction: make sure that 0 <= b <= a.
1751 if (bignum_compare(a
.untagged(), b
.untagged()) == BIGNUM_COMPARISON_LESS
) {
1753 std::swap(size_a
, size_b
);
1756 while (size_a
> 1) {
1757 nbits
= log2(BIGNUM_REF(a
, size_a
- 1));
1758 x
= ((BIGNUM_REF(a
, size_a
- 1) << (BIGNUM_DIGIT_LENGTH
- nbits
)) |
1759 (BIGNUM_REF(a
, size_a
- 2) >> nbits
));
1760 y
= ((size_b
>= size_a
- 1 ? BIGNUM_REF(b
, size_a
- 2) >> nbits
: 0) |
1762 ? BIGNUM_REF(b
, size_a
- 1) << (BIGNUM_DIGIT_LENGTH
- nbits
)
1765 // inner loop of Lehmer's algorithm;
1774 q
= (x
+ (A
- 1)) / (y
- C
);
1794 // no progress; do a Euclidean step
1796 return bignum_trim(a
.untagged());
1798 data_root
<bignum
> e(bignum_trim(a
.untagged()), this);
1799 data_root
<bignum
> f(bignum_trim(b
.untagged()), this);
1800 c
.set_untagged(bignum_remainder(e
.untagged(), f
.untagged()));
1801 if (c
.untagged() == BIGNUM_OUT_OF_BAND
) {
1802 return c
.untagged();
1806 scan_a
= BIGNUM_START_PTR(a
);
1807 scan_b
= BIGNUM_START_PTR(b
);
1808 a_end
= scan_a
+ size_a
;
1809 b_end
= scan_b
+ size_b
;
1810 while (scan_b
< b_end
)
1811 *(scan_a
++) = *(scan_b
++);
1812 while (scan_a
< a_end
)
1817 scan_b
= BIGNUM_START_PTR(b
);
1818 scan_c
= BIGNUM_START_PTR(c
);
1819 size_c
= BIGNUM_LENGTH(c
);
1820 c_end
= scan_c
+ size_c
;
1821 while (scan_c
< c_end
)
1822 *(scan_b
++) = *(scan_c
++);
1823 while (scan_b
< b_end
)
1830 // a, b = A*b - B*a, D*a - C*b if k is odd
1831 // a, b = A*a - B*b, D*b - C*a if k is even
1833 scan_a
= BIGNUM_START_PTR(a
);
1834 scan_b
= BIGNUM_START_PTR(b
);
1837 a_end
= scan_a
+ size_a
;
1838 b_end
= scan_b
+ size_b
;
1842 while (scan_b
< b_end
) {
1843 s
+= (A
* *scan_b
) - (B
* *scan_a
);
1844 t
+= (D
* *scan_a
++) - (C
* *scan_b
++);
1845 *scan_c
++ = (bignum_digit_type
)(s
& BIGNUM_DIGIT_MASK
);
1846 *scan_d
++ = (bignum_digit_type
)(t
& BIGNUM_DIGIT_MASK
);
1847 s
>>= BIGNUM_DIGIT_LENGTH
;
1848 t
>>= BIGNUM_DIGIT_LENGTH
;
1850 while (scan_a
< a_end
) {
1852 t
+= (D
* *scan_a
++);
1853 *scan_c
++ = (bignum_digit_type
)(s
& BIGNUM_DIGIT_MASK
);
1854 //*scan_d++ = (bignum_digit_type) (t & BIGNUM_DIGIT_MASK);
1855 s
>>= BIGNUM_DIGIT_LENGTH
;
1856 t
>>= BIGNUM_DIGIT_LENGTH
;
1859 while (scan_b
< b_end
) {
1860 s
+= (A
* *scan_a
) - (B
* *scan_b
);
1861 t
+= (D
* *scan_b
++) - (C
* *scan_a
++);
1862 *scan_c
++ = (bignum_digit_type
)(s
& BIGNUM_DIGIT_MASK
);
1863 *scan_d
++ = (bignum_digit_type
)(t
& BIGNUM_DIGIT_MASK
);
1864 s
>>= BIGNUM_DIGIT_LENGTH
;
1865 t
>>= BIGNUM_DIGIT_LENGTH
;
1867 while (scan_a
< a_end
) {
1869 t
-= (C
* *scan_a
++);
1870 *scan_c
++ = (bignum_digit_type
)(s
& BIGNUM_DIGIT_MASK
);
1871 //*scan_d++ = (bignum_digit_type) (t & BIGNUM_DIGIT_MASK);
1872 s
>>= BIGNUM_DIGIT_LENGTH
;
1873 t
>>= BIGNUM_DIGIT_LENGTH
;
1876 BIGNUM_ASSERT(s
== 0);
1877 BIGNUM_ASSERT(t
== 0);
1879 // update size_a and size_b to remove any zeros at end
1880 while (size_a
> 0 && *(--scan_a
) == 0)
1882 while (size_b
> 0 && *(--scan_b
) == 0)
1885 BIGNUM_ASSERT(size_a
>= size_b
);
1888 // a fits into a fixnum, so b must too
1889 fixnum xx
= bignum_to_fixnum(a
.untagged());
1890 fixnum yy
= bignum_to_fixnum(b
.untagged());
1893 // usual Euclidean algorithm for longs
1900 return fixnum_to_bignum(xx
);