From d953e40fb30daecb4571e600d64a19a9dd2baac4 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 23 Jul 2021 22:47:44 +0200 Subject: big: Add `pow`. --- core/math/big/basic.odin | 7 ++++++- core/math/big/log.odin | 50 ++++++++++++++++++++++++++++++++++++++++++++---- core/math/big/radix.odin | 4 ++-- 3 files changed, 54 insertions(+), 7 deletions(-) (limited to 'core') diff --git a/core/math/big/basic.odin b/core/math/big/basic.odin index fbb533ddf..18186b38c 100644 --- a/core/math/big/basic.odin +++ b/core/math/big/basic.odin @@ -516,7 +516,7 @@ int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT) -> (err: Error) { } if is_power_of_two(int(multiplier)) { 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); } @@ -648,6 +648,11 @@ int_mul :: proc(dest, src, multiplier: ^Int) -> (err: Error) { mul :: proc { int_mul, int_mul_digit, }; +sqr :: proc(dest, src: ^Int) -> (err: Error) { + return mul(dest, src, src); +} + + /* ========================== Low-level routines diff --git a/core/math/big/log.odin b/core/math/big/log.odin index bb918f690..14b4c593b 100644 --- a/core/math/big/log.odin +++ b/core/math/big/log.odin @@ -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. */ -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 { 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`. */ 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)) { @@ -45,7 +45,49 @@ log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) { 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. @@ -79,7 +121,7 @@ small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) { 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. Therefore, we return 0. diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 8b4abc76d..2dba5d8b4 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -207,7 +207,7 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina shift, count: int; // mask := _WORD(radix - 1); - shift, err = log_n(DIGIT(radix), 2); + shift, err = log(DIGIT(radix), 2); count, err = count_bits(a); digit: _WORD; @@ -263,7 +263,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, e 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; } -- cgit v1.2.3