diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-08-01 19:36:23 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-08-11 20:59:52 +0200 |
| commit | b15ee059ade2db0ce4048bf09c32577137063464 (patch) | |
| tree | 7a383308c7c1e18b598539e51050bab56440de86 /core/math/big/helpers.odin | |
| parent | 50feeaa285b651c8661e25984af4ce58f88c9340 (diff) | |
big: Add `gcd`.
Diffstat (limited to 'core/math/big/helpers.odin')
| -rw-r--r-- | core/math/big/helpers.odin | 68 |
1 files changed, 33 insertions, 35 deletions
diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index d5cf16b33..dc846b4b9 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -504,48 +504,36 @@ count_bits :: proc(a: ^Int) -> (count: int, err: Error) { } /* - Counts the number of LSBs which are zero before the first zero bit + Returns the number of trailing zeroes before the first one. + Differs from regular `ctz` in that 0 returns 0. */ -count_lsb :: proc(a: ^Int) -> (count: int, err: Error) { - if err = clear_if_uninitialized(a); err != .None { - return 0, err; - } - - lnz := []u8{4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; - - q: DIGIT; +int_count_lsb :: proc(a: ^Int) -> (count: int, err: Error) { + if err = clear_if_uninitialized(a); err != .None { return -1, err; } + _ctz :: intrinsics.count_trailing_zeros; /* - Early out for zero. + Easy out. */ - if z, _ := is_zero(a); z { - return 0, .None; - } + if z, _ := is_zero(a); z { return 0, .None; } /* Scan lower digits until non-zero. */ - for count = 0; (count < a.used && a.digit[count] == 0); count += 1 {} - q = a.digit[count]; - count *= _DIGIT_BITS; + x: int; + for x = 0; x < a.used && a.digit[x] == 0; x += 1 {} - /* - Now scan this digit until a 1 is found. - */ - if q & 1 == 0 { - p: DIGIT; - for { - p = q & 15; - count += int(lnz[p]); - q >>= 4; - if p != 0 { - break; - } - } - } - return count, .None; + q := a.digit[x]; + x *= _DIGIT_BITS; + return x + count_lsb(q), .None; +} + +platform_count_lsb :: #force_inline proc(a: $T) -> (count: int) + where intrinsics.type_is_integer(T) && intrinsics.type_is_unsigned(T) { + return int(intrinsics.count_trailing_zeros(a)) if a > 0 else 0; } +count_lsb :: proc { int_count_lsb, platform_count_lsb, }; + int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { when _DIGIT_BITS == 60 { // DIGIT = u64 return DIGIT(rnd.uint64(r)) & _MASK; @@ -602,14 +590,24 @@ _zero_unused :: proc(a: ^Int) { } } -clear_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) { - if !is_initialized(dest) { - return grow(dest, _MIN_DIGIT_COUNT if minimize else _DEFAULT_DIGIT_COUNT); +clear_if_uninitialized_single :: proc(arg: ^Int) -> (err: Error) { + if !is_initialized(arg) { + return grow(arg, _DEFAULT_DIGIT_COUNT); } - return .None; + return err; } +clear_if_uninitialized_multi :: proc(args: ..^Int) -> (err: Error) { + for i in args { + if i != nil && !is_initialized(i) { + e := grow(i, _DEFAULT_DIGIT_COUNT); + if e != .None { err = e; } + } + } + return err; +} +clear_if_uninitialized :: proc {clear_if_uninitialized_single, clear_if_uninitialized_multi, }; /* Allocates several `Int`s at once. |