big: More ZII refactoring.

This commit is contained in:
Jeroen van Rijn
2021-08-11 20:59:50 +02:00
parent 2e372b33a3
commit d9efa6c8b5
5 changed files with 87 additions and 43 deletions
+33 -13
View File
@@ -25,7 +25,11 @@ import "core:intrinsics"
*/ */
int_add :: proc(dest, a, b: ^Int) -> (err: Error) { int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
dest := dest; x := a; y := b; dest := dest; x := a; y := b;
assert_initialized(dest); assert_initialized(a); assert_initialized(b); if dest == nil || a == nil || b == nil {
return .Nil_Pointer_Passed;
} else if !is_initialized(a) || !is_initialized(b) {
return .Int_Not_Initialized;
}
/* /*
Handle both negative or both positive. Handle both negative or both positive.
@@ -56,8 +60,11 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
*/ */
int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) { int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
dest := dest; digit := digit; dest := dest; digit := digit;
assert_initialized(dest); assert_initialized(a); if dest == nil || a == nil {
return .Nil_Pointer_Passed;
} else if !is_initialized(a) {
return .Int_Not_Initialized;
}
/* /*
Fast paths for destination and input Int being the same. Fast paths for destination and input Int being the same.
*/ */
@@ -81,8 +88,7 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
/* /*
Grow destination as required. Grow destination as required.
*/ */
err = grow(dest, a.used + 1); if err = grow(dest, a.used + 1); err != .OK {
if err != .OK {
return err; return err;
} }
@@ -170,7 +176,11 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
*/ */
int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) { int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
dest := dest; x := number; y := decrease; dest := dest; x := number; y := decrease;
assert_initialized(number); assert_initialized(decrease); assert_initialized(dest); if dest == nil || number == nil || decrease == nil {
return .Nil_Pointer_Passed;
} else if !(is_initialized(number) && is_initialized(decrease)) {
return .Int_Not_Initialized;
}
if x.sign != y.sign { if x.sign != y.sign {
/* /*
@@ -210,7 +220,11 @@ int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
*/ */
int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) { int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
dest := dest; digit := digit; dest := dest; digit := digit;
assert_initialized(dest); assert_initialized(a); if dest == nil || a == nil {
return .Nil_Pointer_Passed;
} else if !is_initialized(a) {
return .Int_Not_Initialized;
}
/* /*
Fast paths for destination and input Int being the same. Fast paths for destination and input Int being the same.
@@ -306,7 +320,11 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
*/ */
_int_add :: proc(dest, a, b: ^Int) -> (err: Error) { _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
dest := dest; x := a; y := b; dest := dest; x := a; y := b;
assert_initialized(a); assert_initialized(b); assert_initialized(dest); if dest == nil || a == nil || b == nil {
return .Nil_Pointer_Passed;
} else if !is_initialized(a) || !is_initialized(b) {
return .Int_Not_Initialized;
}
old_used, min_used, max_used, i: int; old_used, min_used, max_used, i: int;
@@ -318,8 +336,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
max_used = y.used; max_used = y.used;
old_used = dest.used; old_used = dest.used;
err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); if err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != .OK {
if err != .OK {
return err; return err;
} }
dest.used = max_used + 1; dest.used = max_used + 1;
@@ -387,15 +404,18 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
*/ */
_int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) { _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
dest := dest; x := number; y := decrease; dest := dest; x := number; y := decrease;
assert_initialized(number); assert_initialized(decrease); assert_initialized(dest); if dest == nil || number == nil || decrease == nil {
return .Nil_Pointer_Passed;
} else if !is_initialized(number) || !is_initialized(decrease) {
return .Int_Not_Initialized;
}
old_used := dest.used; old_used := dest.used;
min_used := y.used; min_used := y.used;
max_used := x.used; max_used := x.used;
i: int; i: int;
err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != .OK {
if err != .OK {
return err; return err;
} }
dest.used = max_used; dest.used = max_used;
+2 -2
View File
@@ -44,9 +44,9 @@ _SQR_TOOM_CUTOFF,
print :: proc(name: string, a: ^Int, base := i8(16)) { print :: proc(name: string, a: ^Int, base := i8(16)) {
as, err := itoa(a, base); as, err := itoa(a, base);
defer delete(as); defer delete(as);
if err == .OK { if err == .OK {
fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, count_bits(a), as); cb, _ := count_bits(a);
fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as);
} else { } else {
fmt.printf("%v (error: %v): %v\n", name, err, a); fmt.printf("%v (error: %v): %v\n", name, err, a);
} }
+33 -15
View File
@@ -328,7 +328,12 @@ minus_one :: proc { int_minus_one, };
power_of_two :: proc(a: ^Int, power: int) -> (err: Error) { power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
assert_initialized(a); /*
Check that `a` is usable.
*/
if a == nil {
return .Nil_Pointer_Passed;
}
if power < 0 || power > _MAX_BIT_COUNT { if power < 0 || power > _MAX_BIT_COUNT {
return .Invalid_Input; return .Invalid_Input;
@@ -356,13 +361,17 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
/* /*
Count bits in an `Int`. Count bits in an `Int`.
*/ */
count_bits :: proc(a: ^Int) -> (count: int) { count_bits :: proc(a: ^Int) -> (count: int, err: Error) {
assert_initialized(a); if a == nil {
return 0, .Nil_Pointer_Passed;
} else if !is_initialized(a) {
return 0, .Int_Not_Initialized;
}
/* /*
Fast path for zero. Fast path for zero.
*/ */
if is_zero(a) { if is_zero(a) {
return 0; return 0, .OK;
} }
/* /*
Get the number of DIGITs and use it. Get the number of DIGITs and use it.
@@ -384,7 +393,12 @@ assert_initialized :: proc(a: ^Int, loc := #caller_location) {
} }
_zero_unused :: proc(a: ^Int) { _zero_unused :: proc(a: ^Int) {
assert_initialized(a); if a == nil {
return;
} else if !is_initialized(a) {
return;
}
if a.used < len(a.digit) { if a.used < len(a.digit) {
mem.zero_slice(a.digit[a.used:]); mem.zero_slice(a.digit[a.used:]);
} }
@@ -397,15 +411,18 @@ _grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
return .OK; return .OK;
} }
clamp :: proc(a: ^Int) { /*
assert_initialized(a); Trim unused digits.
/*
Trim unused digits This is used to ensure that leading zero digits are trimmed and the leading "used" digit will be non-zero.
This is used to ensure that leading zero digits are Typically very fast. Also fixes the sign if there are no more leading digits.
trimmed and the leading "used" digit will be non-zero. */
Typically very fast. Also fixes the sign if there clamp :: proc(a: ^Int) -> (err: Error) {
are no more leading digits. if a == nil {
*/ return .Nil_Pointer_Passed;
} else if !is_initialized(a) {
return .Int_Not_Initialized;
}
for a.used > 0 && a.digit[a.used - 1] == 0 { for a.used > 0 && a.digit[a.used - 1] == 0 {
a.used -= 1; a.used -= 1;
@@ -414,5 +431,6 @@ clamp :: proc(a: ^Int) {
if is_zero(a) { if is_zero(a) {
a.sign = .Zero_or_Positive; a.sign = .Zero_or_Positive;
} }
}
return .OK;
}
+16 -11
View File
@@ -10,7 +10,11 @@ package big
*/ */
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) { log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
assert_initialized(a); if a == nil {
return 0, .Nil_Pointer_Passed;
} else if !is_initialized(a) {
return 0, .Int_Not_Initialized;
}
if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX { if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
return -1, .Invalid_Input; return -1, .Invalid_Input;
} }
@@ -19,14 +23,14 @@ log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
Fast path for bases that are a power of two. Fast path for bases that are a power of two.
*/ */
if is_power_of_two(int(base)) { if is_power_of_two(int(base)) {
return _log_power_of_two(a, base), .OK; return _log_power_of_two(a, base);
} }
/* /*
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)), .OK; return log_n_digit(a.digit[0], DIGIT(base));
} }
// if (MP_HAS(S_MP_LOG)) { // if (MP_HAS(S_MP_LOG)) {
@@ -42,14 +46,15 @@ log_n :: proc{log_n_int, log_n_digit};
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.
Don't call it if it isn't. Don't call it if it isn't.
*/ */
_log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int) { _log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
base := base; base := base;
y: int; y: int;
for y = 0; base & 1 == 0; { for y = 0; base & 1 == 0; {
y += 1; y += 1;
base >>= 1; base >>= 1;
} }
return (count_bits(a) - 1) / y; log, err = count_bits(a);
return (log - 1) / y, err;
} }
/* /*
@@ -69,20 +74,20 @@ small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
return result; return result;
} }
log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int) { log_n_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.
*/ */
if a < base { if a < base {
return 0; return 0, .OK;
} }
/* /*
If a number equals the base, the log is 1. If a number equals the base, the log is 1.
*/ */
if a == base { if a == base {
return 1; return 1, .OK;
} }
N := _WORD(a); N := _WORD(a);
@@ -111,13 +116,13 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int) {
bracket_low = bracket_mid; bracket_low = bracket_mid;
} }
if N == bracket_mid { if N == bracket_mid {
return mid; return mid, .OK;
} }
} }
if bracket_high == N { if bracket_high == N {
return high; return high, .OK;
} else { } else {
return low; return low, .OK;
} }
} }
+3 -2
View File
@@ -198,9 +198,10 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
buffer[available] = 0; buffer[available] = 0;
} }
shift, count: int;
// mask := _WORD(radix - 1); // mask := _WORD(radix - 1);
shift := int(log_n(DIGIT(radix), 2)); shift, err = log_n(DIGIT(radix), 2);
count := int(count_bits(a)); count, err = count_bits(a);
// digit: _WORD; // digit: _WORD;
for offset := 0; offset < count; offset += 4 { for offset := 0; offset < count; offset += 4 {