diff --git a/core/math/bigint/basic.odin b/core/math/bigint/basic.odin index 56ac692ff..c6a36f60f 100644 --- a/core/math/bigint/basic.odin +++ b/core/math/bigint/basic.odin @@ -12,6 +12,12 @@ package bigint import "core:mem" import "core:intrinsics" +/* + =========================== + User-level routines + =========================== +*/ + /* High-level addition. Handles sign. */ @@ -40,6 +46,49 @@ add :: proc(dest, a, b: ^Int) -> (err: Error) { return _sub(dest, x, y); } +/* + High-level subtraction, dest = number - decrease. Handles signs. +*/ +sub :: proc(dest, number, decrease: ^Int) -> (err: Error) { + dest := dest; x := number; y := decrease; + _panic_if_uninitialized(number); _panic_if_uninitialized(decrease); _panic_if_uninitialized(dest); + + if x.sign != y.sign { + /* + Subtract a negative from a positive, OR subtract a positive from a negative. + In either case, ADD their magnitudes and use the sign of the first number. + */ + dest.sign = x.sign; + return _add(dest, x, y); + } + + /* + Subtract a positive from a positive, OR negative from a negative. + First, take the difference between their magnitudes, then... + */ + if cmp_mag(x, y) == .Less_Than { + /* + The second has a larger magnitude. + The result has the *opposite* sign from the first number. + */ + dest.sign = .Negative if is_pos(x) else .Zero_or_Positive; + x, y = y, x; + } else { + /* + The first has a larger or equal magnitude. + Copy the sign from the first. + */ + dest.sign = x.sign; + } + return _sub(dest, x, y); +} + +/* + ========================== + Low-level routines + ========================== +*/ + /* Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7. @@ -121,23 +170,17 @@ _add :: proc(dest, a, b: ^Int) -> (err: Error) { return .OK; } - /* - Low-level subtraction. Assumes |a| > |b|. + Low-level subtraction, dest = number - decrease. Assumes |number| > |decrease|. Handbook of Applied Cryptography, algorithm 14.9. */ -_sub :: proc(dest, a, b: ^Int) -> (err: Error) { - dest := dest; x := a; y := b; - _panic_if_uninitialized(a); _panic_if_uninitialized(b); _panic_if_uninitialized(dest); - - for n in 0..=12 { - dest.digit[n] = DIGIT(n); - dest.used = n+1; - } +_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) { + dest := dest; x := number; y := decrease; + _panic_if_uninitialized(number); _panic_if_uninitialized(decrease); _panic_if_uninitialized(dest); old_used := dest.used; min_used := y.used; - max_used := a.used; + max_used := x.used; i: int; err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); diff --git a/core/math/bigint/example.odin b/core/math/bigint/example.odin index 4b89b193d..0b57d7a8d 100644 --- a/core/math/bigint/example.odin +++ b/core/math/bigint/example.odin @@ -17,11 +17,11 @@ demo :: proc() { a, b, c: ^Int; err: Error; - a, err = init(-21); + a, err = init(21); defer destroy(a); fmt.printf("a: %v, err: %v\n\n", a, err); - b, err = init(42); + b, err = init(-21); defer destroy(b); fmt.printf("b: %v, err: %v\n\n", b, err); @@ -29,7 +29,7 @@ demo :: proc() { c, err = init(); defer destroy(c); - err = add(c, a, b); + err = sub(c, a, b); fmt.printf("c: %v, err: %v\n\n", c, err); }