diff options
| author | gingerBill <bill@gingerbill.org> | 2021-09-06 16:46:57 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-09-06 16:46:57 +0100 |
| commit | 2800d4b8d0698d813584989b74cefed8c7e37a40 (patch) | |
| tree | 23b554635130305a05aa5d2a787a1964fdf66709 /core/math/big/internal.odin | |
| parent | 720884e0f1d6f15c248f8fbe7b86aa146cedac72 (diff) | |
| parent | bc15ce302c0e095fe8db245194e59adc0533eebe (diff) | |
Merge branch 'master' into optional-semicolons
Diffstat (limited to 'core/math/big/internal.odin')
| -rw-r--r-- | core/math/big/internal.odin | 327 |
1 files changed, 295 insertions, 32 deletions
diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 63c702f5e..97630a340 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -1,6 +1,4 @@ //+ignore -package math_big - /* Copyright 2021 Jeroen van Rijn <nom@duclavier.com>. Made available under Odin's BSD-3 license. @@ -31,6 +29,7 @@ package math_big TODO: Handle +/- Infinity and NaN. */ +package math_big import "core:mem" import "core:intrinsics" @@ -137,7 +136,7 @@ internal_int_add_signed :: proc(dest, a, b: ^Int, allocator := context.allocator Subtract the one with the greater magnitude from the other. The result gets the sign of the one with the greater magnitude. */ - if #force_inline internal_cmp_mag(a, b) == -1 { + if #force_inline internal_lt_abs(a, b) { x, y = y, x } @@ -359,7 +358,7 @@ internal_int_sub_signed :: proc(dest, number, decrease: ^Int, allocator := conte Subtract a positive from a positive, OR negative from a negative. First, take the difference between their magnitudes, then... */ - if #force_inline internal_cmp_mag(number, decrease) == -1 { + if #force_inline internal_lt_abs(number, decrease) { /* The second has a larger magnitude. The result has the *opposite* sign from the first number. @@ -546,6 +545,25 @@ internal_int_shl1 :: proc(dest, src: ^Int, allocator := context.allocator) -> (e } /* + Multiply bigint `a` with int `d` and put the result in `dest`. + Like `internal_int_mul_digit` but with an integer as the small input. +*/ +internal_int_mul_integer :: proc(dest, a: ^Int, b: $T, allocator := context.allocator) -> (err: Error) +where intrinsics.type_is_integer(T) && T != DIGIT { + context.allocator = allocator + + t := &Int{} + defer internal_destroy(t) + + /* + DIGIT might be smaller than a long, which excludes the use of `internal_int_mul_digit` here. + */ + internal_set(t, b) or_return + internal_mul(dest, a, t) or_return + return +} + +/* Multiply by a DIGIT. */ internal_int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.allocator) -> (err: Error) { @@ -698,7 +716,7 @@ internal_int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.alloc return err } -internal_mul :: proc { internal_int_mul, internal_int_mul_digit, } +internal_mul :: proc { internal_int_mul, internal_int_mul_digit, internal_int_mul_integer } internal_sqr :: proc (dest, src: ^Int, allocator := context.allocator) -> (res: Error) { /* @@ -719,7 +737,7 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a /* If numerator < denominator then quotient = 0, remainder = numerator. */ - if #force_inline internal_cmp_mag(numerator, denominator) == -1 { + if #force_inline internal_lt_abs(numerator, denominator) { if remainder != nil { internal_copy(remainder, numerator) or_return } @@ -732,7 +750,6 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a if (denominator.used > 2 * MUL_KARATSUBA_CUTOFF) && (denominator.used <= (numerator.used / 3) * 2) { assert(denominator.used >= 160 && numerator.used >= 240, "MUL_KARATSUBA_CUTOFF global not properly set.") err = _private_int_div_recursive(quotient, remainder, numerator, denominator) - // err = #force_inline _private_int_div_school(quotient, remainder, numerator, denominator); } else { when true { err = #force_inline _private_int_div_school(quotient, remainder, numerator, denominator) @@ -856,14 +873,14 @@ internal_int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := c if remainder.used == 0 || denominator.sign == remainder.sign { return nil } - return #force_inline internal_add(remainder, remainder, numerator, allocator) + return #force_inline internal_add(remainder, remainder, denominator, allocator) } internal_int_mod_digit :: proc(numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (remainder: DIGIT, err: Error) { return internal_int_divmod_digit(nil, numerator, denominator, allocator) } -internal_mod :: proc{ internal_int_mod, internal_int_mod_digit} +internal_mod :: proc{ internal_int_mod, internal_int_mod_digit, } /* remainder = (number + addend) % modulus. @@ -942,6 +959,14 @@ internal_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context. return #force_inline _private_int_gcd_lcm(res_gcd, res_lcm, a, b, allocator) } +internal_int_gcd :: proc(res_gcd, a, b: ^Int, allocator := context.allocator) -> (err: Error) { + return #force_inline _private_int_gcd_lcm(res_gcd, nil, a, b, allocator) +} + +internal_int_lcm :: proc(res_lcm, a, b: ^Int, allocator := context.allocator) -> (err: Error) { + return #force_inline _private_int_gcd_lcm(nil, res_lcm, a, b, allocator) +} + /* remainder = numerator % (1 << bits) @@ -993,12 +1018,20 @@ internal_int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator : */ /* + This procedure returns the allocated capacity of an Int. + Assumes `a` not to be `nil`. +*/ +internal_int_allocated_cap :: #force_inline proc(a: ^Int) -> (cap: int) { + raw := transmute(mem.Raw_Dynamic_Array)a.digit + return raw.cap +} + +/* This procedure will return `true` if the `Int` is initialized, `false` if not. Assumes `a` not to be `nil`. */ internal_int_is_initialized :: #force_inline proc(a: ^Int) -> (initialized: bool) { - raw := transmute(mem.Raw_Dynamic_Array)a.digit - return raw.cap >= _MIN_DIGIT_COUNT + return internal_int_allocated_cap(a) >= _MIN_DIGIT_COUNT } internal_is_initialized :: proc { internal_int_is_initialized, } @@ -1091,6 +1124,7 @@ internal_is_power_of_two :: proc { internal_int_is_power_of_two, } Expects `a` and `b` both to be valid `Int`s, i.e. initialized and not `nil`. */ internal_int_compare :: #force_inline proc(a, b: ^Int) -> (comparison: int) { + assert_if_nil(a, b) a_is_negative := #force_inline internal_is_negative(a) /* @@ -1114,6 +1148,7 @@ internal_cmp :: internal_compare Expects: `a` and `b` both to be valid `Int`s, i.e. initialized and not `nil`. */ internal_int_compare_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (comparison: int) { + assert_if_nil(a) a_is_negative := #force_inline internal_is_negative(a) switch { @@ -1145,6 +1180,7 @@ internal_cmp_digit :: internal_compare_digit Compare the magnitude of two `Int`s, unsigned. */ internal_int_compare_magnitude :: #force_inline proc(a, b: ^Int) -> (comparison: int) { + assert_if_nil(a, b) /* Compare based on used digits. */ @@ -1172,6 +1208,177 @@ internal_int_compare_magnitude :: #force_inline proc(a, b: ^Int) -> (comparison: internal_compare_magnitude :: proc { internal_int_compare_magnitude, } internal_cmp_mag :: internal_compare_magnitude + +/* + bool := a < b +*/ +internal_int_less_than :: #force_inline proc(a, b: ^Int) -> (less_than: bool) { + return internal_cmp(a, b) == -1 +} + +/* + bool := a < b +*/ +internal_int_less_than_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (less_than: bool) { + return internal_cmp_digit(a, b) == -1 +} + +/* + bool := |a| < |b| + Compares the magnitudes only, ignores the sign. +*/ +internal_int_less_than_abs :: #force_inline proc(a, b: ^Int) -> (less_than: bool) { + return internal_cmp_mag(a, b) == -1 +} + +internal_less_than :: proc { + internal_int_less_than, + internal_int_less_than_digit, +} +internal_lt :: internal_less_than + +internal_less_than_abs :: proc { + internal_int_less_than_abs, +} +internal_lt_abs :: internal_less_than_abs + + +/* + bool := a <= b +*/ +internal_int_less_than_or_equal :: #force_inline proc(a, b: ^Int) -> (less_than_or_equal: bool) { + return internal_cmp(a, b) <= 0 +} + +/* + bool := a <= b +*/ +internal_int_less_than_or_equal_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (less_than_or_equal: bool) { + return internal_cmp_digit(a, b) <= 0 +} + +/* + bool := |a| <= |b| + Compares the magnitudes only, ignores the sign. +*/ +internal_int_less_than_or_equal_abs :: #force_inline proc(a, b: ^Int) -> (less_than_or_equal: bool) { + return internal_cmp_mag(a, b) <= 0 +} + +internal_less_than_or_equal :: proc { + internal_int_less_than_or_equal, + internal_int_less_than_or_equal_digit, +} +internal_lte :: internal_less_than_or_equal + +internal_less_than_or_equal_abs :: proc { + internal_int_less_than_or_equal_abs, +} +internal_lte_abs :: internal_less_than_or_equal_abs + + +/* + bool := a == b +*/ +internal_int_equals :: #force_inline proc(a, b: ^Int) -> (equals: bool) { + return internal_cmp(a, b) == 0 +} + +/* + bool := a == b +*/ +internal_int_equals_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (equals: bool) { + return internal_cmp_digit(a, b) == 0 +} + +/* + bool := |a| == |b| + Compares the magnitudes only, ignores the sign. +*/ +internal_int_equals_abs :: #force_inline proc(a, b: ^Int) -> (equals: bool) { + return internal_cmp_mag(a, b) == 0 +} + +internal_equals :: proc { + internal_int_equals, + internal_int_equals_digit, +} +internal_eq :: internal_equals + +internal_equals_abs :: proc { + internal_int_equals_abs, +} +internal_eq_abs :: internal_equals_abs + + +/* + bool := a >= b +*/ +internal_int_greater_than_or_equal :: #force_inline proc(a, b: ^Int) -> (greater_than_or_equal: bool) { + return internal_cmp(a, b) >= 0 +} + +/* + bool := a >= b +*/ +internal_int_greater_than_or_equal_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (greater_than_or_equal: bool) { + return internal_cmp_digit(a, b) >= 0 +} + +/* + bool := |a| >= |b| + Compares the magnitudes only, ignores the sign. +*/ +internal_int_greater_than_or_equal_abs :: #force_inline proc(a, b: ^Int) -> (greater_than_or_equal: bool) { + return internal_cmp_mag(a, b) >= 0 +} + +internal_greater_than_or_equal :: proc { + internal_int_greater_than_or_equal, + internal_int_greater_than_or_equal_digit, +} +internal_gte :: internal_greater_than_or_equal + +internal_greater_than_or_equal_abs :: proc { + internal_int_greater_than_or_equal_abs, +} +internal_gte_abs :: internal_greater_than_or_equal_abs + + +/* + bool := a > b +*/ +internal_int_greater_than :: #force_inline proc(a, b: ^Int) -> (greater_than: bool) { + return internal_cmp(a, b) == 1 +} + +/* + bool := a > b +*/ +internal_int_greater_than_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (greater_than: bool) { + return internal_cmp_digit(a, b) == 1 +} + +/* + bool := |a| > |b| + Compares the magnitudes only, ignores the sign. +*/ +internal_int_greater_than_abs :: #force_inline proc(a, b: ^Int) -> (greater_than: bool) { + return internal_cmp_mag(a, b) == 1 +} + +internal_greater_than :: proc { + internal_int_greater_than, + internal_int_greater_than_digit, +} +internal_gt :: internal_greater_than + +internal_greater_than_abs :: proc { + internal_int_greater_than_abs, +} +internal_gt_abs :: internal_greater_than_abs + + /* Check if remainders are possible squares - fast exclude non-squares. @@ -1229,7 +1436,7 @@ internal_int_is_square :: proc(a: ^Int, allocator := context.allocator) -> (squa sqrt(t, a) or_return sqr(t, t) or_return - square = internal_cmp_mag(t, a) == 0 + square = internal_eq_abs(t, a) return } @@ -1461,7 +1668,7 @@ internal_int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (e internal_add(t2, t1, x) or_return internal_shr(y, t2, 1) or_return - if c := internal_cmp(y, x); c == 0 || c == 1 { + if internal_gte(y, x) { internal_swap(dest, x) return nil } @@ -1576,8 +1783,8 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca Number of rounds is at most log_2(root). If it is more it got stuck, so break out of the loop and do the rest manually. */ - if ilog2 -= 1; ilog2 == 0 { break } - if internal_cmp(t1, t2) == 0 { break } + if ilog2 -= 1; ilog2 == 0 { break } + if internal_eq(t1, t2) { break } iterations += 1 if iterations == MAX_ITERATIONS_ROOT_N { @@ -1615,7 +1822,7 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca for { internal_pow(t2, t1, n) or_return - if internal_cmp(t2, a) != 1 { break } + if internal_lt(t2, a) { break } internal_sub(t1, t1, DIGIT(1)) or_return @@ -1651,8 +1858,7 @@ internal_int_destroy :: proc(integers: ..^Int) { integers := integers for a in &integers { - raw := transmute(mem.Raw_Dynamic_Array)a.digit - if raw.cap > 0 { + if internal_int_allocated_cap(a) > 0 { mem.zero_slice(a.digit[:]) free(&a.digit[0]) } @@ -1692,7 +1898,7 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al return nil } -internal_set :: proc { internal_int_set_from_integer, internal_int_copy } +internal_set :: proc { internal_int_set_from_integer, internal_int_copy, int_atoi } internal_copy_digits :: #force_inline proc(dest, src: ^Int, digits: int, offset := int(0)) -> (err: Error) { #force_inline internal_error_if_immutable(dest) or_return @@ -1821,12 +2027,12 @@ internal_int_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.alloc /* For all n in N and n > 0, n = 0 mod 1. */ - if internal_is_positive(a) && internal_cmp(b, 1) == 0 { return internal_zero(dest) } + if internal_is_positive(a) && internal_eq(b, 1) { return internal_zero(dest) } /* `b` cannot be negative and has to be > 1 */ - if internal_is_negative(b) && internal_cmp(b, 1) != 1 { return .Invalid_Argument } + if internal_is_negative(b) || internal_gt(b, 1) { return .Invalid_Argument } /* If the modulus is odd we can use a faster routine instead. @@ -1839,9 +2045,20 @@ internal_invmod :: proc{ internal_int_inverse_modulo, } /* Helpers to extract values from the `Int`. + Offset is zero indexed. */ +internal_int_bitfield_extract_bool :: proc(a: ^Int, offset: int) -> (val: bool, err: Error) { + limb := offset / _DIGIT_BITS + if limb < 0 || limb >= a.used { return false, .Invalid_Argument } + i := _WORD(1 << _WORD((offset % _DIGIT_BITS))) + return bool(_WORD(a.digit[limb]) & i), nil +} + internal_int_bitfield_extract_single :: proc(a: ^Int, offset: int) -> (bit: _WORD, err: Error) { - return #force_inline int_bitfield_extract(a, offset, 1) + limb := offset / _DIGIT_BITS + if limb < 0 || limb >= a.used { return 0, .Invalid_Argument } + i := _WORD(1 << _WORD((offset % _DIGIT_BITS))) + return 1 if ((_WORD(a.digit[limb]) & i) != 0) else 0, nil } internal_int_bitfield_extract :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) #no_bounds_check { @@ -1900,6 +2117,34 @@ internal_int_bitfield_extract :: proc(a: ^Int, offset, count: int) -> (res: _WOR } /* + Helpers to (un)set a bit in an Int. + Offset is zero indexed. +*/ +internal_int_bitfield_set_single :: proc(a: ^Int, offset: int) -> (err: Error) { + limb := offset / _DIGIT_BITS + if limb < 0 || limb >= a.used { return .Invalid_Argument } + i := DIGIT(1 << uint((offset % _DIGIT_BITS))) + a.digit[limb] |= i + return +} + +internal_int_bitfield_unset_single :: proc(a: ^Int, offset: int) -> (err: Error) { + limb := offset / _DIGIT_BITS + if limb < 0 || limb >= a.used { return .Invalid_Argument } + i := DIGIT(1 << uint((offset % _DIGIT_BITS))) + a.digit[limb] &= _MASK - i + return +} + +internal_int_bitfield_toggle_single :: proc(a: ^Int, offset: int) -> (err: Error) { + limb := offset / _DIGIT_BITS + if limb < 0 || limb >= a.used { return .Invalid_Argument } + i := DIGIT(1 << uint((offset % _DIGIT_BITS))) + a.digit[limb] ~= i + return +} + +/* Resize backing store. We don't need to pass the allocator, because the storage itself stores it. @@ -1914,23 +2159,23 @@ internal_int_shrink :: proc(a: ^Int) -> (err: Error) { internal_shrink :: proc { internal_int_shrink, } internal_int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) { - raw := transmute(mem.Raw_Dynamic_Array)a.digit - /* We need at least _MIN_DIGIT_COUNT or a.used digits, whichever is bigger. The caller is asking for `digits`. Let's be accomodating. */ + cap := internal_int_allocated_cap(a) + needed := max(_MIN_DIGIT_COUNT, a.used, digits) if !allow_shrink { - needed = max(needed, raw.cap) + needed = max(needed, cap) } /* If not yet iniialized, initialize the `digit` backing with the allocator we were passed. */ - if raw.cap == 0 { + if cap == 0 { a.digit = make([dynamic]DIGIT, needed, allocator) - } else if raw.cap != needed { + } else if cap != needed { /* `[dynamic]DIGIT` already knows what allocator was used for it, so resize will do the right thing. */ @@ -2558,9 +2803,27 @@ internal_int_count_lsb :: proc(a: ^Int) -> (count: int, err: Error) { x: int #no_bounds_check for x = 0; x < a.used && a.digit[x] == 0; x += 1 {} - q := a.digit[x] - x *= _DIGIT_BITS - x += internal_count_lsb(q) + when true { + q := a.digit[x] + x *= _DIGIT_BITS + x += internal_count_lsb(q) + } else { + lnz := []int{ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + } + + q := a.digit[x] + x *= _DIGIT_BITS + if q & 1 == 0 { + p: DIGIT + for { + p = q & 15 + x += lnz[p] + q >>= 4 + if p != 0 { break } + } + } + } return x, nil } @@ -2583,7 +2846,7 @@ internal_int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) { return 0 // We shouldn't get here. } -internal_int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) { +internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) { context.allocator = allocator bits := bits @@ -2608,7 +2871,7 @@ internal_int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator : dest.used = digits return nil } -internal_rand :: proc { internal_int_rand, } +internal_random :: proc { internal_int_random, } /* Internal helpers. |