mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
big: More ZII refactoring.
This commit is contained in:
+33
-13
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user