mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 20:00:09 +00:00
big: Fast square method.
This commit is contained in:
+74
-14
@@ -8,12 +8,11 @@ package big
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
This file contains basic arithmetic operations like `add`, `sub`, `div`, ...
|
||||
This file contains basic arithmetic operations like `add`, `sub`, `mul`, `div`, ...
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:intrinsics"
|
||||
import "core:fmt"
|
||||
|
||||
/*
|
||||
===========================
|
||||
@@ -26,15 +25,9 @@ import "core:fmt"
|
||||
*/
|
||||
int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
dest := dest; x := a; y := b;
|
||||
if err = clear_if_uninitialized(a); err != .None {
|
||||
return err;
|
||||
}
|
||||
if err = clear_if_uninitialized(b); err != .None {
|
||||
return err;
|
||||
}
|
||||
if err = clear_if_uninitialized(dest); err != .None {
|
||||
return err;
|
||||
}
|
||||
if err = clear_if_uninitialized(a); err != .None { return err; }
|
||||
if err = clear_if_uninitialized(b); err != .None { return err; }
|
||||
if err = clear_if_uninitialized(dest); err != .None { return err; }
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
We can now safely ignore errors from comparison routines.
|
||||
@@ -599,7 +592,7 @@ int_mul :: proc(dest, src, multiplier: ^Int) -> (err: Error) {
|
||||
digits := src.used + multiplier.used + 1;
|
||||
neg := src.sign != multiplier.sign;
|
||||
|
||||
if false && src == multiplier {
|
||||
if src == multiplier {
|
||||
/*
|
||||
Do we need to square?
|
||||
*/
|
||||
@@ -614,7 +607,7 @@ int_mul :: proc(dest, src, multiplier: ^Int) -> (err: Error) {
|
||||
/* Fast comba? */
|
||||
// err = s_mp_sqr_comba(a, c);
|
||||
} else {
|
||||
// err = s_mp_sqr(a, c);
|
||||
err = _int_sqr(dest, src);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@@ -646,7 +639,6 @@ int_mul :: proc(dest, src, multiplier: ^Int) -> (err: Error) {
|
||||
*/
|
||||
// err = s_mp_mul_comba(a, b, c, digs);
|
||||
} else {
|
||||
fmt.println("Hai");
|
||||
err = _int_mul(dest, src, multiplier, digits);
|
||||
}
|
||||
}
|
||||
@@ -889,4 +881,72 @@ _int_mul :: proc(dest, a, b: ^Int, digits: int) -> (err: Error) {
|
||||
swap(dest, t);
|
||||
destroy(t);
|
||||
return clamp(dest);
|
||||
}
|
||||
|
||||
/*
|
||||
Low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16
|
||||
*/
|
||||
_int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
|
||||
pa := src.used;
|
||||
|
||||
t := &Int{}; ix, iy: int;
|
||||
/*
|
||||
Grow `t` to maximum needed size, or `_DEFAULT_DIGIT_COUNT`, whichever is bigger.
|
||||
*/
|
||||
if err = grow(t, min((2 * pa) + 1, _DEFAULT_DIGIT_COUNT)); err != .None { return err; }
|
||||
t.used = (2 * pa) + 1;
|
||||
|
||||
for ix = 0; ix < pa; ix += 1 {
|
||||
carry := DIGIT(0);
|
||||
/*
|
||||
First calculate the digit at 2*ix; calculate double precision result.
|
||||
*/
|
||||
r := _WORD(t.digit[ix+ix]) + _WORD(src.digit[ix] * src.digit[ix]);
|
||||
|
||||
/*
|
||||
Store lower part in result.
|
||||
*/
|
||||
t.digit[ix+ix] = DIGIT(r & _WORD(_MASK));
|
||||
|
||||
/*
|
||||
Get the carry.
|
||||
*/
|
||||
carry = DIGIT(r >> _DIGIT_BITS);
|
||||
|
||||
for iy = ix + 1; iy < pa; iy += 1 {
|
||||
/*
|
||||
First calculate the product.
|
||||
*/
|
||||
r = _WORD(src.digit[ix]) * _WORD(src.digit[iy]);
|
||||
|
||||
/* Now calculate the double precision result. Nte we use
|
||||
* addition instead of *2 since it's easier to optimize
|
||||
*/
|
||||
r = _WORD(t.digit[ix+iy]) + r + r + _WORD(carry);
|
||||
|
||||
/*
|
||||
Store lower part.
|
||||
*/
|
||||
t.digit[ix+iy] = DIGIT(r & _WORD(_MASK));
|
||||
|
||||
/*
|
||||
Get carry.
|
||||
*/
|
||||
carry = DIGIT(r >> _DIGIT_BITS);
|
||||
}
|
||||
/*
|
||||
Propagate upwards.
|
||||
*/
|
||||
for carry != 0 {
|
||||
r = _WORD(t.digit[ix+iy]) + _WORD(carry);
|
||||
t.digit[ix+iy] = DIGIT(r & _WORD(_MASK));
|
||||
carry = DIGIT(r >> _WORD(_DIGIT_BITS));
|
||||
iy += 1;
|
||||
}
|
||||
}
|
||||
|
||||
err = clamp(t);
|
||||
swap(dest, t);
|
||||
destroy(t);
|
||||
return err;
|
||||
}
|
||||
Reference in New Issue
Block a user