From d4d863c4db6fcc893ff3a04ff3ef4ca1ef757f4c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 22 Jul 2021 18:12:19 +0200 Subject: [PATCH] big: Add `mod_power_of_two`. --- core/math/big/basic.odin | 59 ++++++++++++++++++++++++++++++++------ core/math/big/example.odin | 8 +++--- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/core/math/big/basic.odin b/core/math/big/basic.odin index 7a3bbf751..42db8b88e 100644 --- a/core/math/big/basic.odin +++ b/core/math/big/basic.odin @@ -322,7 +322,7 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) { carry := dest.digit[i] >> ((size_of(DIGIT) * 8) - 1); dest.digit[i] &= _MASK; } - } + } zero_count := old_used - dest.used; /* @@ -374,13 +374,13 @@ int_halve :: proc(dest, src: ^Int) -> (err: Error) { Shift the current digit, add in carry and store. */ dest.digit[x] = (src_digit >> 1) | (fwd_carry << (_DIGIT_BITS - 1)); - /* - Forward carry to next iteration. - */ - fwd_carry = carry; - } + /* + Forward carry to next iteration. + */ + fwd_carry = carry; + } - zero_count := old_used - dest.used; + zero_count := old_used - dest.used; /* Zero remainder. */ @@ -447,7 +447,7 @@ int_double :: proc(dest, src: ^Int) -> (err: Error) { */ dest.digit[dest.used] = 1; } - zero_count := old_used - dest.used; + zero_count := old_used - dest.used; /* Zero remainder. */ @@ -463,6 +463,49 @@ int_double :: proc(dest, src: ^Int) -> (err: Error) { double :: proc { int_double, }; shl1 :: double; + +/* + dest = src % (2^power); +*/ +int_mod_power_of_two :: proc(dest, src: ^Int, power: int) -> (err: Error) { + dest := dest; src := src; + if err = clear_if_uninitialized(dest); err != .None { + return err; + } + if err = clear_if_uninitialized(src); err != .None { + return err; + } + + if power < 0 { return .Invalid_Argument; } + if power == 0 { return zero(dest); } + + /* + If the modulus is larger than the value, return the value. + */ + err = copy(dest, src); + if power >= (src.used * _DIGIT_BITS) || err != .None { + return; + } + + /* + Zero digits above the last digit of the modulus. + */ + zero_count := (power / _DIGIT_BITS) + 0 if (power % _DIGIT_BITS == 0) else 1; + /* + Zero remainder. + */ + if zero_count > 0 { + mem.zero_slice(dest.digit[zero_count:]); + } + + /* + Clear the digit that is not completely outside/inside the modulus. + */ + dest.digit[power / _DIGIT_BITS] &= DIGIT(1 << DIGIT(power % _DIGIT_BITS)) - DIGIT(1); + return clamp(dest); +} +mod_power_of_two :: proc { int_mod_power_of_two, }; + /* ========================== Low-level routines diff --git a/core/math/big/example.odin b/core/math/big/example.odin index 014e19af6..1b8503233 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -57,16 +57,16 @@ demo :: proc() { a, b, c := &Int{}, &Int{}, &Int{}; defer destroy(a, b, c); - err = set(a, 0); - a.used = 2; - a.digit[1] = 1; + err = set(a, -512); err = set(b, 1); err = set(c, -4); + + err = mod_power_of_two(a, a, 10); fmt.printf("%v (%v)\n", int_get_float(a)); - print("a", a, 16); + print("a", a, 10); print("b", b, 10); print("c", c, 10);