Chez Scheme: improve multiplication with trailing 0s
Multiplying bignums with trailing 0s is common enough to be worth a special case.
This commit is contained in:
parent
0cb9643fcb
commit
35116f6015
|
@ -313,6 +313,7 @@ extern ptr S_gcd PROTO((ptr x, ptr y));
|
||||||
extern ptr S_ash PROTO((ptr x, ptr n));
|
extern ptr S_ash PROTO((ptr x, ptr n));
|
||||||
extern ptr S_big_positive_bit_field PROTO((ptr x, ptr fxstart, ptr fxend));
|
extern ptr S_big_positive_bit_field PROTO((ptr x, ptr fxstart, ptr fxend));
|
||||||
extern ptr S_integer_length PROTO((ptr x));
|
extern ptr S_integer_length PROTO((ptr x));
|
||||||
|
extern ptr S_big_trailing_zero_bits PROTO((ptr x));
|
||||||
extern ptr S_big_first_bit_set PROTO((ptr x));
|
extern ptr S_big_first_bit_set PROTO((ptr x));
|
||||||
extern double S_random_double PROTO((U32 m1, U32 m2,
|
extern double S_random_double PROTO((U32 m1, U32 m2,
|
||||||
U32 m3, U32 m4, double scale));
|
U32 m3, U32 m4, double scale));
|
||||||
|
|
|
@ -1481,6 +1481,23 @@ ptr S_big_positive_bit_field(ptr x, ptr fxstart, ptr fxend) {
|
||||||
return copy_normalize(tc, &BIGIT(W(tc), 0), wl, 0);
|
return copy_normalize(tc, &BIGIT(W(tc), 0), wl, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* returns a lower bound on the number of trailing 0 bits in the
|
||||||
|
binary representation: */
|
||||||
|
ptr S_big_trailing_zero_bits(ptr x) {
|
||||||
|
bigit *xp = &BIGIT(x, 0);
|
||||||
|
iptr xl = BIGLEN(x), i;
|
||||||
|
|
||||||
|
for (i = xl; i-- > 0; ) {
|
||||||
|
if (xp[i] != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = (xl - 1) - i;
|
||||||
|
i *= bigit_bits;
|
||||||
|
|
||||||
|
return FIX(i);
|
||||||
|
}
|
||||||
|
|
||||||
/* logical operations simulate two's complement operations using the
|
/* logical operations simulate two's complement operations using the
|
||||||
following general strategy:
|
following general strategy:
|
||||||
|
|
||||||
|
|
|
@ -1765,6 +1765,7 @@ void S_prim5_init() {
|
||||||
Sforeign_symbol("(cs)s_big_positive_bit_field", (void *)S_big_positive_bit_field);
|
Sforeign_symbol("(cs)s_big_positive_bit_field", (void *)S_big_positive_bit_field);
|
||||||
Sforeign_symbol("(cs)s_big_eq", (void *)S_big_eq);
|
Sforeign_symbol("(cs)s_big_eq", (void *)S_big_eq);
|
||||||
Sforeign_symbol("(cs)s_big_lt", (void *)S_big_lt);
|
Sforeign_symbol("(cs)s_big_lt", (void *)S_big_lt);
|
||||||
|
Sforeign_symbol("(cs)s_big_trailing_zero_bits", (void *)S_big_trailing_zero_bits);
|
||||||
Sforeign_symbol("(cs)s_bigoddp", (void *)s_bigoddp);
|
Sforeign_symbol("(cs)s_bigoddp", (void *)s_bigoddp);
|
||||||
Sforeign_symbol("(cs)s_div", (void *)S_div);
|
Sforeign_symbol("(cs)s_div", (void *)S_div);
|
||||||
Sforeign_symbol("(cs)s_float", (void *)s_float);
|
Sforeign_symbol("(cs)s_float", (void *)s_float);
|
||||||
|
|
|
@ -2197,6 +2197,7 @@
|
||||||
[else (nonnumber-error who x)])])))
|
[else (nonnumber-error who x)])])))
|
||||||
|
|
||||||
(set! $*
|
(set! $*
|
||||||
|
(let ([$bignum-trailing-zero-bits (foreign-procedure "(cs)s_big_trailing_zero_bits" (ptr) ptr)])
|
||||||
(lambda (who x y)
|
(lambda (who x y)
|
||||||
(cond
|
(cond
|
||||||
[(and (fixnum? y) ($fxu< (#3%fx+ y 1) 3))
|
[(and (fixnum? y) ($fxu< (#3%fx+ y 1) 3))
|
||||||
|
@ -2247,7 +2248,17 @@
|
||||||
[else
|
[else
|
||||||
(- c1 (karatsuba (- x-lo x-hi) (- y-lo y-hi)))])])])
|
(- c1 (karatsuba (- x-lo x-hi) (- y-lo y-hi)))])])])
|
||||||
(+ c0 (integer-ash (+ c0 c1-c2) k) (integer-ash c1 (fx* 2 k))))]))
|
(+ c0 (integer-ash (+ c0 c1-c2) k) (integer-ash c1 (fx* 2 k))))]))
|
||||||
(karatsuba x y)))]
|
;; Multiplying numbers with trailing 0s is common, so
|
||||||
|
;; check for that case:
|
||||||
|
(let ([xz ($bignum-trailing-zero-bits x)]
|
||||||
|
[yz (if (bignum? y) ($bignum-trailing-zero-bits y) 0)])
|
||||||
|
(let ([z (fx+ xz yz)])
|
||||||
|
(if (fx= z 0)
|
||||||
|
(karatsuba x y)
|
||||||
|
(bitwise-arithmetic-shift-left
|
||||||
|
(karatsuba (bitwise-arithmetic-shift-right x xz)
|
||||||
|
(bitwise-arithmetic-shift-right y yz))
|
||||||
|
z))))))]
|
||||||
[(ratnum?) (/ (* x ($ratio-numerator y)) ($ratio-denominator y))]
|
[(ratnum?) (/ (* x ($ratio-numerator y)) ($ratio-denominator y))]
|
||||||
[($exactnum? $inexactnum?)
|
[($exactnum? $inexactnum?)
|
||||||
(make-rectangular (* x (real-part y)) (* x (imag-part y)))]
|
(make-rectangular (* x (real-part y)) (* x (imag-part y)))]
|
||||||
|
@ -2281,7 +2292,7 @@
|
||||||
[c (real-part y)] [d (imag-part y)])
|
[c (real-part y)] [d (imag-part y)])
|
||||||
(make-rectangular (- (* a c) (* b d)) (+ (* a d) (* b c))))]
|
(make-rectangular (- (* a c) (* b d)) (+ (* a d) (* b c))))]
|
||||||
[else (nonnumber-error who y)])]
|
[else (nonnumber-error who y)])]
|
||||||
[else (nonnumber-error who x)])])))
|
[else (nonnumber-error who x)])]))))
|
||||||
|
|
||||||
(set! $-
|
(set! $-
|
||||||
(lambda (who x y)
|
(lambda (who x y)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user