big: Add pow.

This commit is contained in:
Jeroen van Rijn
2021-08-11 20:59:51 +02:00
parent c3a4d7dda2
commit d953e40fb3
3 changed files with 54 additions and 7 deletions
+6 -1
View File
@@ -516,7 +516,7 @@ int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT) -> (err: Error) {
} }
if is_power_of_two(int(multiplier)) { if is_power_of_two(int(multiplier)) {
ix: int; ix: int;
if ix, err = log_n(multiplier, 2); err != .None { return err; } if ix, err = log(multiplier, 2); err != .None { return err; }
return shl(dest, src, ix); return shl(dest, src, ix);
} }
@@ -648,6 +648,11 @@ int_mul :: proc(dest, src, multiplier: ^Int) -> (err: Error) {
mul :: proc { int_mul, int_mul_digit, }; mul :: proc { int_mul, int_mul_digit, };
sqr :: proc(dest, src: ^Int) -> (err: Error) {
return mul(dest, src, src);
}
/* /*
========================== ==========================
Low-level routines Low-level routines
+46 -4
View File
@@ -9,7 +9,7 @@ package big
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
*/ */
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) { int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error) {
if base < 2 || DIGIT(base) > _DIGIT_MAX { if base < 2 || DIGIT(base) > _DIGIT_MAX {
return -1, .Invalid_Argument; return -1, .Invalid_Argument;
} }
@@ -35,7 +35,7 @@ log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
Fast path for `Int`s that fit within a single `DIGIT`. Fast path for `Int`s that fit within a single `DIGIT`.
*/ */
if a.used == 1 { if a.used == 1 {
return log_n_digit(a.digit[0], DIGIT(base)); return log(a.digit[0], DIGIT(base));
} }
// if (MP_HAS(S_MP_LOG)) { // if (MP_HAS(S_MP_LOG)) {
@@ -45,7 +45,49 @@ log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
return -1, .Unimplemented; return -1, .Unimplemented;
} }
log_n :: proc{log_n_int, log_n_digit}; log :: proc { int_log, int_log_digit, };
/*
Calculate c = a**b using a square-multiply algorithm.
*/
int_pow :: proc(dest, base: ^Int, power: int) -> (err: Error) {
if err = clear_if_uninitialized(dest); err != .None { return err; }
if err = clear_if_uninitialized(base); err != .None { return err; }
// if ((err = mp_init_copy(&g, a)) != MP_OKAY) {
// return err;
// }
// /* set initial result */
// mp_set(c, 1uL);
// while (b > 0) {
// /* if the bit is set multiply */
// if ((b & 1) != 0) {
// if ((err = mp_mul(c, &g, c)) != MP_OKAY) {
// goto LBL_ERR;
// }
// }
// /* square */
// if (b > 1) {
// if ((err = mp_sqr(&g, &g)) != MP_OKAY) {
// goto LBL_ERR;
// }
// }
// /* shift to next bit */
// b >>= 1;
// }
// LBL_ERR:
// mp_clear(&g);
// return err;
return err;
}
pow :: proc { int_pow, };
/* /*
Returns the log2 of an `Int`, provided `base` is a power of two. Returns the log2 of an `Int`, provided `base` is a power of two.
@@ -79,7 +121,7 @@ small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
return result; return result;
} }
log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) { int_log_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
/* /*
If the number is smaller than the base, it fits within a fraction. If the number is smaller than the base, it fits within a fraction.
Therefore, we return 0. Therefore, we return 0.
+2 -2
View File
@@ -207,7 +207,7 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
shift, count: int; shift, count: int;
// mask := _WORD(radix - 1); // mask := _WORD(radix - 1);
shift, err = log_n(DIGIT(radix), 2); shift, err = log(DIGIT(radix), 2);
count, err = count_bits(a); count, err = count_bits(a);
digit: _WORD; digit: _WORD;
@@ -263,7 +263,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, e
digit = a.digit, digit = a.digit,
}; };
if size, err = log_n(t, DIGIT(radix)); err != .None { if size, err = log(t, DIGIT(radix)); err != .None {
return 0, err; return 0, err;
} }