mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-22 21:54:59 -07:00
bigint: refactor to big.Int instead of bigint.Int.
This commit is contained in:
@@ -1,455 +1,454 @@
|
||||
package bigint
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-2 license.
|
||||
|
||||
A BigInt implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
This file contains basic arithmetic operations like `add` and `sub`.
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:intrinsics"
|
||||
import "core:fmt"
|
||||
|
||||
/*
|
||||
===========================
|
||||
User-level routines
|
||||
===========================
|
||||
*/
|
||||
|
||||
/*
|
||||
High-level addition. Handles sign.
|
||||
*/
|
||||
add_two_ints :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
dest := dest; x := a; y := b;
|
||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||
|
||||
/*
|
||||
Handle both negative or both positive.
|
||||
*/
|
||||
if x.sign == y.sign {
|
||||
dest.sign = x.sign;
|
||||
return _add(dest, x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
One positive, the other negative.
|
||||
Subtract the one with the greater magnitude from the other.
|
||||
The result gets the sign of the one with the greater magnitude.
|
||||
*/
|
||||
if cmp_mag(x, y) == .Less_Than {
|
||||
x, y = y, x;
|
||||
}
|
||||
|
||||
dest.sign = x.sign;
|
||||
return _sub(dest, x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
Adds the unsigned `DIGIT` immediate to an `Int`,
|
||||
such that the `DIGIT` doesn't have to be turned into an `Int` first.
|
||||
|
||||
dest = a + digit;
|
||||
*/
|
||||
add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
||||
dest := dest; x := a; digit := digit;
|
||||
assert_initialized(dest); assert_initialized(a);
|
||||
|
||||
/*
|
||||
Fast paths for destination and input Int being the same.
|
||||
*/
|
||||
if dest == a {
|
||||
/*
|
||||
Fast path for dest.digit[0] + digit fits in dest.digit[0] without overflow.
|
||||
*/
|
||||
if is_pos(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
|
||||
dest.digit[0] += digit;
|
||||
return .OK;
|
||||
}
|
||||
/*
|
||||
Can be subtracted from dest.digit[0] without underflow.
|
||||
*/
|
||||
if is_neg(a) && (dest.digit[0] > digit) {
|
||||
dest.digit[0] -= digit;
|
||||
return .OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
err = grow(dest, a.used + 1);
|
||||
if err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
|
||||
*/
|
||||
if is_neg(a) && (a.used > 1 || a.digit[0] >= digit) {
|
||||
/*
|
||||
Temporarily fix `a`'s sign.
|
||||
*/
|
||||
t := a;
|
||||
t.sign = .Zero_or_Positive;
|
||||
/*
|
||||
dest = |a| - digit
|
||||
*/
|
||||
err = sub(dest, t, digit);
|
||||
/*
|
||||
Restore sign and set `dest` sign.
|
||||
*/
|
||||
dest.sign = .Negative;
|
||||
clamp(dest);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
Remember the currently used number of digits in `dest`.
|
||||
*/
|
||||
old_used := dest.used;
|
||||
|
||||
/*
|
||||
If `a` is positive
|
||||
*/
|
||||
if is_pos(a) {
|
||||
/*
|
||||
Add digits, use `carry`.
|
||||
*/
|
||||
i: int;
|
||||
carry := digit;
|
||||
for i = 0; i < a.used; i += 1 {
|
||||
dest.digit[i] = a.digit[i] + carry;
|
||||
carry = dest.digit[i] >> _DIGIT_BITS;
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
/*
|
||||
Set final carry.
|
||||
*/
|
||||
dest.digit[i] = carry;
|
||||
/*
|
||||
Set `dest` size.
|
||||
*/
|
||||
dest.used = a.used + 1;
|
||||
} else {
|
||||
/*
|
||||
`a` was negative and |a| < digit.
|
||||
*/
|
||||
dest.used = 1;
|
||||
/*
|
||||
The result is a single DIGIT.
|
||||
*/
|
||||
dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
|
||||
}
|
||||
/*
|
||||
Sign is always positive.
|
||||
*/
|
||||
dest.sign = .Zero_or_Positive;
|
||||
|
||||
zero_count := old_used - dest.used;
|
||||
/*
|
||||
Zero remainder.
|
||||
*/
|
||||
if zero_count > 0 {
|
||||
mem.zero_slice(dest.digit[dest.used:][:zero_count]);
|
||||
}
|
||||
/*
|
||||
Adjust dest.used based on leading zeroes.
|
||||
*/
|
||||
clamp(dest);
|
||||
|
||||
return .OK;
|
||||
}
|
||||
|
||||
add :: proc{add_two_ints, add_digit};
|
||||
|
||||
/*
|
||||
High-level subtraction, dest = number - decrease. Handles signs.
|
||||
*/
|
||||
sub_two_ints :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
||||
dest := dest; x := number; y := decrease;
|
||||
assert_initialized(number); assert_initialized(decrease); assert_initialized(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);
|
||||
}
|
||||
|
||||
/*
|
||||
Adds the unsigned `DIGIT` immediate to an `Int`,
|
||||
such that the `DIGIT` doesn't have to be turned into an `Int` first.
|
||||
|
||||
dest = a - digit;
|
||||
*/
|
||||
sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
||||
dest := dest; x := a; digit := digit;
|
||||
assert_initialized(dest); assert_initialized(a);
|
||||
|
||||
/*
|
||||
Fast paths for destination and input Int being the same.
|
||||
*/
|
||||
if dest == a {
|
||||
/*
|
||||
Fast path for `dest` is negative and unsigned addition doesn't overflow the lowest digit.
|
||||
*/
|
||||
if is_neg(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
|
||||
dest.digit[0] += digit;
|
||||
return .OK;
|
||||
}
|
||||
/*
|
||||
Can be subtracted from dest.digit[0] without underflow.
|
||||
*/
|
||||
if is_pos(a) && (dest.digit[0] > digit) {
|
||||
dest.digit[0] -= digit;
|
||||
return .OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
err = grow(dest, a.used + 1);
|
||||
if err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
If `a` is negative, just do an unsigned addition (with fudged signs).
|
||||
*/
|
||||
if is_neg(a) {
|
||||
t := a;
|
||||
t.sign = .Zero_or_Positive;
|
||||
|
||||
err = add(dest, t, digit);
|
||||
dest.sign = .Negative;
|
||||
|
||||
clamp(dest);
|
||||
return err;
|
||||
}
|
||||
|
||||
old_used := dest.used;
|
||||
|
||||
/*
|
||||
if `a`<= digit, simply fix the single digit.
|
||||
*/
|
||||
if a.used == 1 && (a.digit[0] <= digit || is_zero(a)) {
|
||||
dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
|
||||
dest.sign = .Negative;
|
||||
dest.used = 1;
|
||||
} else {
|
||||
dest.sign = .Zero_or_Positive;
|
||||
dest.used = a.used;
|
||||
|
||||
/*
|
||||
Subtract with carry.
|
||||
*/
|
||||
carry := digit;
|
||||
|
||||
for i := 0; i < a.used; i += 1 {
|
||||
dest.digit[i] = a.digit[i] - carry;
|
||||
carry := dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
}
|
||||
|
||||
zero_count := old_used - dest.used;
|
||||
/*
|
||||
Zero remainder.
|
||||
*/
|
||||
if zero_count > 0 {
|
||||
mem.zero_slice(dest.digit[dest.used:][:zero_count]);
|
||||
}
|
||||
/*
|
||||
Adjust dest.used based on leading zeroes.
|
||||
*/
|
||||
clamp(dest);
|
||||
|
||||
return .OK;
|
||||
}
|
||||
|
||||
sub :: proc{sub_two_ints, sub_digit};
|
||||
|
||||
/*
|
||||
==========================
|
||||
Low-level routines
|
||||
==========================
|
||||
*/
|
||||
|
||||
/*
|
||||
Low-level addition, unsigned.
|
||||
Handbook of Applied Cryptography, algorithm 14.7.
|
||||
*/
|
||||
_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
dest := dest; x := a; y := b;
|
||||
assert_initialized(a); assert_initialized(b); assert_initialized(dest);
|
||||
|
||||
old_used, min_used, max_used, i: int;
|
||||
|
||||
if x.used < y.used {
|
||||
x, y = y, x;
|
||||
}
|
||||
|
||||
min_used = x.used;
|
||||
max_used = y.used;
|
||||
old_used = dest.used;
|
||||
|
||||
err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT));
|
||||
if err != .OK {
|
||||
return err;
|
||||
}
|
||||
dest.used = max_used + 1;
|
||||
|
||||
/* Zero the carry */
|
||||
carry := DIGIT(0);
|
||||
|
||||
for i = 0; i < min_used; i += 1 {
|
||||
/*
|
||||
Compute the sum one _DIGIT at a time.
|
||||
dest[i] = a[i] + b[i] + carry;
|
||||
*/
|
||||
dest.digit[i] = x.digit[i] + y.digit[i] + carry;
|
||||
|
||||
/*
|
||||
Compute carry
|
||||
*/
|
||||
carry = dest.digit[i] >> _DIGIT_BITS;
|
||||
/*
|
||||
Mask away carry from result digit.
|
||||
*/
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
|
||||
if min_used != max_used {
|
||||
/*
|
||||
Now copy higher words, if any, in A+B.
|
||||
If A or B has more digits, add those in.
|
||||
*/
|
||||
for ; i < max_used; i += 1 {
|
||||
dest.digit[i] = x.digit[i] + carry;
|
||||
/*
|
||||
Compute carry
|
||||
*/
|
||||
carry = dest.digit[i] >> _DIGIT_BITS;
|
||||
/*
|
||||
Mask away carry from result digit.
|
||||
*/
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Add remaining carry.
|
||||
*/
|
||||
dest.digit[i] = carry;
|
||||
|
||||
zero_count := old_used - dest.used;
|
||||
/*
|
||||
Zero remainder.
|
||||
*/
|
||||
if zero_count > 0 {
|
||||
mem.zero_slice(dest.digit[dest.used:][:zero_count]);
|
||||
}
|
||||
/*
|
||||
Adjust dest.used based on leading zeroes.
|
||||
*/
|
||||
clamp(dest);
|
||||
|
||||
return .OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Low-level subtraction, dest = number - decrease. Assumes |number| > |decrease|.
|
||||
Handbook of Applied Cryptography, algorithm 14.9.
|
||||
*/
|
||||
_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
||||
dest := dest; x := number; y := decrease;
|
||||
assert_initialized(number); assert_initialized(decrease); assert_initialized(dest);
|
||||
|
||||
old_used := dest.used;
|
||||
min_used := y.used;
|
||||
max_used := x.used;
|
||||
i: int;
|
||||
|
||||
err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT));
|
||||
if err != .OK {
|
||||
return err;
|
||||
}
|
||||
dest.used = max_used;
|
||||
|
||||
borrow := DIGIT(0);
|
||||
|
||||
for i = 0; i < min_used; i += 1 {
|
||||
dest.digit[i] = (x.digit[i] - y.digit[i] - borrow);
|
||||
/*
|
||||
borrow = carry bit of dest[i]
|
||||
Note this saves performing an AND operation since if a carry does occur,
|
||||
it will propagate all the way to the MSB.
|
||||
As a result a single shift is enough to get the carry.
|
||||
*/
|
||||
borrow = dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
|
||||
/*
|
||||
Clear borrow from dest[i].
|
||||
*/
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
Now copy higher words if any, e.g. if A has more digits than B
|
||||
*/
|
||||
for ; i < max_used; i += 1 {
|
||||
dest.digit[i] = x.digit[i] - borrow;
|
||||
/*
|
||||
borrow = carry bit of dest[i]
|
||||
Note this saves performing an AND operation since if a carry does occur,
|
||||
it will propagate all the way to the MSB.
|
||||
As a result a single shift is enough to get the carry.
|
||||
*/
|
||||
borrow = dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
|
||||
/*
|
||||
Clear borrow from dest[i].
|
||||
*/
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
|
||||
zero_count := old_used - dest.used;
|
||||
/*
|
||||
Zero remainder.
|
||||
*/
|
||||
if zero_count > 0 {
|
||||
mem.zero_slice(dest.digit[dest.used:][:zero_count]);
|
||||
}
|
||||
/*
|
||||
Adjust dest.used based on leading zeroes.
|
||||
*/
|
||||
clamp(dest);
|
||||
return .OK;
|
||||
package big
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-2 license.
|
||||
|
||||
A BigInt implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
This file contains basic arithmetic operations like `add` and `sub`.
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:intrinsics"
|
||||
|
||||
/*
|
||||
===========================
|
||||
User-level routines
|
||||
===========================
|
||||
*/
|
||||
|
||||
/*
|
||||
High-level addition. Handles sign.
|
||||
*/
|
||||
add_two_ints :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
dest := dest; x := a; y := b;
|
||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||
|
||||
/*
|
||||
Handle both negative or both positive.
|
||||
*/
|
||||
if x.sign == y.sign {
|
||||
dest.sign = x.sign;
|
||||
return _add(dest, x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
One positive, the other negative.
|
||||
Subtract the one with the greater magnitude from the other.
|
||||
The result gets the sign of the one with the greater magnitude.
|
||||
*/
|
||||
if cmp_mag(x, y) == .Less_Than {
|
||||
x, y = y, x;
|
||||
}
|
||||
|
||||
dest.sign = x.sign;
|
||||
return _sub(dest, x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
Adds the unsigned `DIGIT` immediate to an `Int`,
|
||||
such that the `DIGIT` doesn't have to be turned into an `Int` first.
|
||||
|
||||
dest = a + digit;
|
||||
*/
|
||||
add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
||||
dest := dest; digit := digit;
|
||||
assert_initialized(dest); assert_initialized(a);
|
||||
|
||||
/*
|
||||
Fast paths for destination and input Int being the same.
|
||||
*/
|
||||
if dest == a {
|
||||
/*
|
||||
Fast path for dest.digit[0] + digit fits in dest.digit[0] without overflow.
|
||||
*/
|
||||
if is_pos(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
|
||||
dest.digit[0] += digit;
|
||||
return .OK;
|
||||
}
|
||||
/*
|
||||
Can be subtracted from dest.digit[0] without underflow.
|
||||
*/
|
||||
if is_neg(a) && (dest.digit[0] > digit) {
|
||||
dest.digit[0] -= digit;
|
||||
return .OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
err = grow(dest, a.used + 1);
|
||||
if err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
|
||||
*/
|
||||
if is_neg(a) && (a.used > 1 || a.digit[0] >= digit) {
|
||||
/*
|
||||
Temporarily fix `a`'s sign.
|
||||
*/
|
||||
t := a;
|
||||
t.sign = .Zero_or_Positive;
|
||||
/*
|
||||
dest = |a| - digit
|
||||
*/
|
||||
err = sub(dest, t, digit);
|
||||
/*
|
||||
Restore sign and set `dest` sign.
|
||||
*/
|
||||
dest.sign = .Negative;
|
||||
clamp(dest);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
Remember the currently used number of digits in `dest`.
|
||||
*/
|
||||
old_used := dest.used;
|
||||
|
||||
/*
|
||||
If `a` is positive
|
||||
*/
|
||||
if is_pos(a) {
|
||||
/*
|
||||
Add digits, use `carry`.
|
||||
*/
|
||||
i: int;
|
||||
carry := digit;
|
||||
for i = 0; i < a.used; i += 1 {
|
||||
dest.digit[i] = a.digit[i] + carry;
|
||||
carry = dest.digit[i] >> _DIGIT_BITS;
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
/*
|
||||
Set final carry.
|
||||
*/
|
||||
dest.digit[i] = carry;
|
||||
/*
|
||||
Set `dest` size.
|
||||
*/
|
||||
dest.used = a.used + 1;
|
||||
} else {
|
||||
/*
|
||||
`a` was negative and |a| < digit.
|
||||
*/
|
||||
dest.used = 1;
|
||||
/*
|
||||
The result is a single DIGIT.
|
||||
*/
|
||||
dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
|
||||
}
|
||||
/*
|
||||
Sign is always positive.
|
||||
*/
|
||||
dest.sign = .Zero_or_Positive;
|
||||
|
||||
zero_count := old_used - dest.used;
|
||||
/*
|
||||
Zero remainder.
|
||||
*/
|
||||
if zero_count > 0 {
|
||||
mem.zero_slice(dest.digit[dest.used:][:zero_count]);
|
||||
}
|
||||
/*
|
||||
Adjust dest.used based on leading zeroes.
|
||||
*/
|
||||
clamp(dest);
|
||||
|
||||
return .OK;
|
||||
}
|
||||
|
||||
add :: proc{add_two_ints, add_digit};
|
||||
|
||||
/*
|
||||
High-level subtraction, dest = number - decrease. Handles signs.
|
||||
*/
|
||||
sub_two_ints :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
||||
dest := dest; x := number; y := decrease;
|
||||
assert_initialized(number); assert_initialized(decrease); assert_initialized(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);
|
||||
}
|
||||
|
||||
/*
|
||||
Adds the unsigned `DIGIT` immediate to an `Int`,
|
||||
such that the `DIGIT` doesn't have to be turned into an `Int` first.
|
||||
|
||||
dest = a - digit;
|
||||
*/
|
||||
sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
||||
dest := dest; digit := digit;
|
||||
assert_initialized(dest); assert_initialized(a);
|
||||
|
||||
/*
|
||||
Fast paths for destination and input Int being the same.
|
||||
*/
|
||||
if dest == a {
|
||||
/*
|
||||
Fast path for `dest` is negative and unsigned addition doesn't overflow the lowest digit.
|
||||
*/
|
||||
if is_neg(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
|
||||
dest.digit[0] += digit;
|
||||
return .OK;
|
||||
}
|
||||
/*
|
||||
Can be subtracted from dest.digit[0] without underflow.
|
||||
*/
|
||||
if is_pos(a) && (dest.digit[0] > digit) {
|
||||
dest.digit[0] -= digit;
|
||||
return .OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
err = grow(dest, a.used + 1);
|
||||
if err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
If `a` is negative, just do an unsigned addition (with fudged signs).
|
||||
*/
|
||||
if is_neg(a) {
|
||||
t := a;
|
||||
t.sign = .Zero_or_Positive;
|
||||
|
||||
err = add(dest, t, digit);
|
||||
dest.sign = .Negative;
|
||||
|
||||
clamp(dest);
|
||||
return err;
|
||||
}
|
||||
|
||||
old_used := dest.used;
|
||||
|
||||
/*
|
||||
if `a`<= digit, simply fix the single digit.
|
||||
*/
|
||||
if a.used == 1 && (a.digit[0] <= digit || is_zero(a)) {
|
||||
dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
|
||||
dest.sign = .Negative;
|
||||
dest.used = 1;
|
||||
} else {
|
||||
dest.sign = .Zero_or_Positive;
|
||||
dest.used = a.used;
|
||||
|
||||
/*
|
||||
Subtract with carry.
|
||||
*/
|
||||
carry := digit;
|
||||
|
||||
for i := 0; i < a.used; i += 1 {
|
||||
dest.digit[i] = a.digit[i] - carry;
|
||||
carry := dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
}
|
||||
|
||||
zero_count := old_used - dest.used;
|
||||
/*
|
||||
Zero remainder.
|
||||
*/
|
||||
if zero_count > 0 {
|
||||
mem.zero_slice(dest.digit[dest.used:][:zero_count]);
|
||||
}
|
||||
/*
|
||||
Adjust dest.used based on leading zeroes.
|
||||
*/
|
||||
clamp(dest);
|
||||
|
||||
return .OK;
|
||||
}
|
||||
|
||||
sub :: proc{sub_two_ints, sub_digit};
|
||||
|
||||
/*
|
||||
==========================
|
||||
Low-level routines
|
||||
==========================
|
||||
*/
|
||||
|
||||
/*
|
||||
Low-level addition, unsigned.
|
||||
Handbook of Applied Cryptography, algorithm 14.7.
|
||||
*/
|
||||
_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
dest := dest; x := a; y := b;
|
||||
assert_initialized(a); assert_initialized(b); assert_initialized(dest);
|
||||
|
||||
old_used, min_used, max_used, i: int;
|
||||
|
||||
if x.used < y.used {
|
||||
x, y = y, x;
|
||||
}
|
||||
|
||||
min_used = x.used;
|
||||
max_used = y.used;
|
||||
old_used = dest.used;
|
||||
|
||||
err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT));
|
||||
if err != .OK {
|
||||
return err;
|
||||
}
|
||||
dest.used = max_used + 1;
|
||||
|
||||
/* Zero the carry */
|
||||
carry := DIGIT(0);
|
||||
|
||||
for i = 0; i < min_used; i += 1 {
|
||||
/*
|
||||
Compute the sum one _DIGIT at a time.
|
||||
dest[i] = a[i] + b[i] + carry;
|
||||
*/
|
||||
dest.digit[i] = x.digit[i] + y.digit[i] + carry;
|
||||
|
||||
/*
|
||||
Compute carry
|
||||
*/
|
||||
carry = dest.digit[i] >> _DIGIT_BITS;
|
||||
/*
|
||||
Mask away carry from result digit.
|
||||
*/
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
|
||||
if min_used != max_used {
|
||||
/*
|
||||
Now copy higher words, if any, in A+B.
|
||||
If A or B has more digits, add those in.
|
||||
*/
|
||||
for ; i < max_used; i += 1 {
|
||||
dest.digit[i] = x.digit[i] + carry;
|
||||
/*
|
||||
Compute carry
|
||||
*/
|
||||
carry = dest.digit[i] >> _DIGIT_BITS;
|
||||
/*
|
||||
Mask away carry from result digit.
|
||||
*/
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Add remaining carry.
|
||||
*/
|
||||
dest.digit[i] = carry;
|
||||
|
||||
zero_count := old_used - dest.used;
|
||||
/*
|
||||
Zero remainder.
|
||||
*/
|
||||
if zero_count > 0 {
|
||||
mem.zero_slice(dest.digit[dest.used:][:zero_count]);
|
||||
}
|
||||
/*
|
||||
Adjust dest.used based on leading zeroes.
|
||||
*/
|
||||
clamp(dest);
|
||||
|
||||
return .OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Low-level subtraction, dest = number - decrease. Assumes |number| > |decrease|.
|
||||
Handbook of Applied Cryptography, algorithm 14.9.
|
||||
*/
|
||||
_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
||||
dest := dest; x := number; y := decrease;
|
||||
assert_initialized(number); assert_initialized(decrease); assert_initialized(dest);
|
||||
|
||||
old_used := dest.used;
|
||||
min_used := y.used;
|
||||
max_used := x.used;
|
||||
i: int;
|
||||
|
||||
err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT));
|
||||
if err != .OK {
|
||||
return err;
|
||||
}
|
||||
dest.used = max_used;
|
||||
|
||||
borrow := DIGIT(0);
|
||||
|
||||
for i = 0; i < min_used; i += 1 {
|
||||
dest.digit[i] = (x.digit[i] - y.digit[i] - borrow);
|
||||
/*
|
||||
borrow = carry bit of dest[i]
|
||||
Note this saves performing an AND operation since if a carry does occur,
|
||||
it will propagate all the way to the MSB.
|
||||
As a result a single shift is enough to get the carry.
|
||||
*/
|
||||
borrow = dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
|
||||
/*
|
||||
Clear borrow from dest[i].
|
||||
*/
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
Now copy higher words if any, e.g. if A has more digits than B
|
||||
*/
|
||||
for ; i < max_used; i += 1 {
|
||||
dest.digit[i] = x.digit[i] - borrow;
|
||||
/*
|
||||
borrow = carry bit of dest[i]
|
||||
Note this saves performing an AND operation since if a carry does occur,
|
||||
it will propagate all the way to the MSB.
|
||||
As a result a single shift is enough to get the carry.
|
||||
*/
|
||||
borrow = dest.digit[i] >> ((size_of(DIGIT) * 8) - 1);
|
||||
/*
|
||||
Clear borrow from dest[i].
|
||||
*/
|
||||
dest.digit[i] &= _MASK;
|
||||
}
|
||||
|
||||
zero_count := old_used - dest.used;
|
||||
/*
|
||||
Zero remainder.
|
||||
*/
|
||||
if zero_count > 0 {
|
||||
mem.zero_slice(dest.digit[dest.used:][:zero_count]);
|
||||
}
|
||||
/*
|
||||
Adjust dest.used based on leading zeroes.
|
||||
*/
|
||||
clamp(dest);
|
||||
return .OK;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package bigint
|
||||
package big
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
@@ -35,7 +35,13 @@ _DEFAULT_SQR_KARATSUBA_CUTOFF :: 120;
|
||||
_DEFAULT_MUL_TOOM_CUTOFF :: 350;
|
||||
_DEFAULT_SQR_TOOM_CUTOFF :: 400;
|
||||
|
||||
/*
|
||||
TODO(Jeroen): Decide whether to turn `Sign` into `Flags :: bit_set{Flag; u8}`.
|
||||
This would hold the sign and float class, as appropriate, and would allow us
|
||||
to set an `Int` to +/- Inf, or NaN.
|
||||
|
||||
The operations would need to be updated to propagate these as expected.
|
||||
*/
|
||||
Sign :: enum u8 {
|
||||
Zero_or_Positive = 0,
|
||||
Negative = 1,
|
||||
@@ -44,8 +50,8 @@ Sign :: enum u8 {
|
||||
Int :: struct {
|
||||
used: int,
|
||||
allocated: int,
|
||||
sign: Sign,
|
||||
digit: [dynamic]DIGIT,
|
||||
sign: Sign,
|
||||
};
|
||||
|
||||
Comparison_Flag :: enum i8 {
|
||||
@@ -72,7 +78,7 @@ Error :: enum i8 {
|
||||
Primality_Flag :: enum u8 {
|
||||
Blum_Blum_Shub = 0, /* BBS style prime */
|
||||
Safe = 1, /* Safe prime (p-1)/2 == prime */
|
||||
Second_MSB_On = 3, /* force 2nd MSB to 1 */
|
||||
Second_MSB_On = 3, /* force 2nd MSB to 1 */
|
||||
};
|
||||
Primality_Flags :: bit_set[Primality_Flag; u8];
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
@echo off
|
||||
odin run . -vet
|
||||
@@ -1,4 +1,4 @@
|
||||
package bigint
|
||||
package big
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
@@ -1,5 +1,5 @@
|
||||
//+ignore
|
||||
package bigint
|
||||
package big
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
@@ -60,9 +60,9 @@ demo :: proc() {
|
||||
defer destroy(b);
|
||||
defer destroy(c);
|
||||
|
||||
a, err = init(1+4+16+64);
|
||||
a, err = init(512);
|
||||
|
||||
b, err = init(1+2+8+32+128);
|
||||
b, err = init(a);
|
||||
|
||||
c, err = init(-4);
|
||||
|
||||
@@ -108,4 +108,10 @@ main :: proc() {
|
||||
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location);
|
||||
}
|
||||
}
|
||||
if len(ta.bad_free_array) > 0 {
|
||||
fmt.println("Bad frees:");
|
||||
for v in ta.bad_free_array {
|
||||
fmt.println(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package bigint
|
||||
package big
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
@@ -11,7 +11,6 @@ package bigint
|
||||
|
||||
import "core:mem"
|
||||
import "core:intrinsics"
|
||||
import "core:fmt"
|
||||
|
||||
/*
|
||||
Deallocates the backing memory of an Int.
|
||||
@@ -62,7 +61,7 @@ init_new :: proc(allocator_zeroes := true, allocator := context.allocator, size
|
||||
Initialize from a signed or unsigned integer.
|
||||
Inits a new `Int` and then calls the appropriate `set` routine.
|
||||
*/
|
||||
init_new_integer :: proc(u: $T, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) where intrinsics.type_is_integer(T) {
|
||||
init_from_integer :: proc(src: $T, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) where intrinsics.type_is_integer(T) {
|
||||
|
||||
n := _DEFAULT_DIGIT_COUNT;
|
||||
if minimize {
|
||||
@@ -71,12 +70,27 @@ init_new_integer :: proc(u: $T, minimize := false, allocator_zeroes := true, all
|
||||
|
||||
a, err = init_new(allocator_zeroes, allocator, n);
|
||||
if err == .OK {
|
||||
set(a, u, minimize);
|
||||
set(a, src, minimize);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
init :: proc{init_new, init_new_integer};
|
||||
/*
|
||||
Initialize an `Int` as a copy from another `Int`.
|
||||
*/
|
||||
init_copy :: proc(src: ^Int, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) {
|
||||
if !is_initialized(src) {
|
||||
return nil, .Invalid_Input;
|
||||
}
|
||||
|
||||
a, err = init_new(allocator_zeroes, allocator, src.used);
|
||||
if err == .OK {
|
||||
copy(a, src);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
init :: proc{init_new, init_from_integer, init_copy};
|
||||
|
||||
/*
|
||||
Helpers to set an `Int` to a specific value.
|
||||
@@ -123,7 +137,7 @@ copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Grow `dest` to fit `src`.
|
||||
*/
|
||||
if err = grow(dest, min(src.used, _DEFAULT_DIGIT_COUNT)); err != .OK {
|
||||
if err = grow(dest, src.used); err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -226,6 +240,9 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
|
||||
return 1 if ((a.digit[limb] & i) != 0) else 0, .OK;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Optimize.
|
||||
*/
|
||||
extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
||||
if count > _WORD_BITS || count < 1 {
|
||||
return 0, .Invalid_Input;
|
||||
@@ -1,125 +1,123 @@
|
||||
package bigint
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-2 license.
|
||||
|
||||
A BigInt implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
*/
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
|
||||
assert_initialized(a);
|
||||
if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
|
||||
return -1, .Invalid_Input;
|
||||
}
|
||||
|
||||
/*
|
||||
Fast path for bases that are a power of two.
|
||||
*/
|
||||
if is_power_of_two(int(base)) {
|
||||
return _log_power_of_two(a, base), .OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Fast path for `Int`s that fit within a single `DIGIT`.
|
||||
*/
|
||||
if a.used == 1 {
|
||||
return log_n_digit(a.digit[0], DIGIT(base)), .OK;
|
||||
}
|
||||
|
||||
// if (MP_HAS(S_MP_LOG)) {
|
||||
// return s_mp_log(a, (mp_digit)base, c);
|
||||
// }
|
||||
|
||||
return -1, .Unimplemented;
|
||||
}
|
||||
|
||||
log_n :: proc{log_n_int, log_n_digit};
|
||||
|
||||
/*
|
||||
Returns the log2 of an `Int`, provided `base` is a power of two.
|
||||
Don't call it if it isn't.
|
||||
*/
|
||||
_log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int) {
|
||||
base := base;
|
||||
y: int;
|
||||
for y = 0; base & 1 == 0; {
|
||||
y += 1;
|
||||
base >>= 1;
|
||||
}
|
||||
return (count_bits(a) - 1) / y;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
|
||||
exponent := exponent; base := base;
|
||||
result = _WORD(1);
|
||||
|
||||
for exponent != 0 {
|
||||
if exponent & 1 == 1 {
|
||||
result *= base;
|
||||
}
|
||||
exponent >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int) {
|
||||
/*
|
||||
If the number is smaller than the base, it fits within a fraction.
|
||||
Therefore, we return 0.
|
||||
*/
|
||||
if a < base {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
If a number equals the base, the log is 1.
|
||||
*/
|
||||
if a == base {
|
||||
return 1;
|
||||
}
|
||||
|
||||
N := _WORD(a);
|
||||
bracket_low := _WORD(1);
|
||||
bracket_high := _WORD(base);
|
||||
high := 1;
|
||||
low := 0;
|
||||
|
||||
for bracket_high < N {
|
||||
low = high;
|
||||
bracket_low = bracket_high;
|
||||
high <<= 1;
|
||||
bracket_high *= bracket_high;
|
||||
}
|
||||
|
||||
for high - low > 1 {
|
||||
mid := (low + high) >> 1;
|
||||
bracket_mid := bracket_low * small_pow(_WORD(base), _WORD(mid - low));
|
||||
|
||||
if N < bracket_mid {
|
||||
high = mid;
|
||||
bracket_high = bracket_mid;
|
||||
}
|
||||
if N > bracket_mid {
|
||||
low = mid;
|
||||
bracket_low = bracket_mid;
|
||||
}
|
||||
if N == bracket_mid {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
|
||||
if bracket_high == N {
|
||||
return high;
|
||||
} else {
|
||||
return low;
|
||||
}
|
||||
package big
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-2 license.
|
||||
|
||||
A BigInt implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
*/
|
||||
|
||||
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
|
||||
assert_initialized(a);
|
||||
if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
|
||||
return -1, .Invalid_Input;
|
||||
}
|
||||
|
||||
/*
|
||||
Fast path for bases that are a power of two.
|
||||
*/
|
||||
if is_power_of_two(int(base)) {
|
||||
return _log_power_of_two(a, base), .OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Fast path for `Int`s that fit within a single `DIGIT`.
|
||||
*/
|
||||
if a.used == 1 {
|
||||
return log_n_digit(a.digit[0], DIGIT(base)), .OK;
|
||||
}
|
||||
|
||||
// if (MP_HAS(S_MP_LOG)) {
|
||||
// return s_mp_log(a, (mp_digit)base, c);
|
||||
// }
|
||||
|
||||
return -1, .Unimplemented;
|
||||
}
|
||||
|
||||
log_n :: proc{log_n_int, log_n_digit};
|
||||
|
||||
/*
|
||||
Returns the log2 of an `Int`, provided `base` is a power of two.
|
||||
Don't call it if it isn't.
|
||||
*/
|
||||
_log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int) {
|
||||
base := base;
|
||||
y: int;
|
||||
for y = 0; base & 1 == 0; {
|
||||
y += 1;
|
||||
base >>= 1;
|
||||
}
|
||||
return (count_bits(a) - 1) / y;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
|
||||
exponent := exponent; base := base;
|
||||
result = _WORD(1);
|
||||
|
||||
for exponent != 0 {
|
||||
if exponent & 1 == 1 {
|
||||
result *= base;
|
||||
}
|
||||
exponent >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int) {
|
||||
/*
|
||||
If the number is smaller than the base, it fits within a fraction.
|
||||
Therefore, we return 0.
|
||||
*/
|
||||
if a < base {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
If a number equals the base, the log is 1.
|
||||
*/
|
||||
if a == base {
|
||||
return 1;
|
||||
}
|
||||
|
||||
N := _WORD(a);
|
||||
bracket_low := _WORD(1);
|
||||
bracket_high := _WORD(base);
|
||||
high := 1;
|
||||
low := 0;
|
||||
|
||||
for bracket_high < N {
|
||||
low = high;
|
||||
bracket_low = bracket_high;
|
||||
high <<= 1;
|
||||
bracket_high *= bracket_high;
|
||||
}
|
||||
|
||||
for high - low > 1 {
|
||||
mid := (low + high) >> 1;
|
||||
bracket_mid := bracket_low * small_pow(_WORD(base), _WORD(mid - low));
|
||||
|
||||
if N < bracket_mid {
|
||||
high = mid;
|
||||
bracket_high = bracket_mid;
|
||||
}
|
||||
if N > bracket_mid {
|
||||
low = mid;
|
||||
bracket_low = bracket_mid;
|
||||
}
|
||||
if N == bracket_mid {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
|
||||
if bracket_high == N {
|
||||
return high;
|
||||
} else {
|
||||
return low;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package big
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-2 license.
|
||||
|
||||
A BigInt implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
This file contains logical operations like `and`, `or` and `xor`.
|
||||
*/
|
||||
|
||||
/*
|
||||
The `and`, `or` and `xor` binops differ in two lines only.
|
||||
We could handle those with a switch, but that adds overhead.
|
||||
*/
|
||||
|
||||
/*
|
||||
2's complement `and`, returns `dest = a & b;`
|
||||
*/
|
||||
and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||
|
||||
used := max(a.used, b.used) + 1;
|
||||
neg: bool;
|
||||
|
||||
neg = is_neg(a) && is_neg(b);
|
||||
|
||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||
|
||||
/*
|
||||
Grow the destination to accomodate the result.
|
||||
*/
|
||||
if err = grow(dest, used); err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
for i := 0; i < used; i += 1 {
|
||||
x, y: DIGIT;
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if is_neg(a) {
|
||||
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||
x = ac & _MASK;
|
||||
ac >>= _DIGIT_BITS;
|
||||
} else {
|
||||
x = 0 if i >= a.used else a.digit[i];
|
||||
}
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if is_neg(a) {
|
||||
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||
y = bc & _MASK;
|
||||
bc >>= _DIGIT_BITS;
|
||||
} else {
|
||||
y = 0 if i >= b.used else b.digit[i];
|
||||
}
|
||||
|
||||
dest.digit[i] = x & y;
|
||||
|
||||
/*
|
||||
Convert to to sign-magnitude if negative.
|
||||
*/
|
||||
if neg {
|
||||
cc += ~dest.digit[i] & _MASK;
|
||||
dest.digit[i] = cc & _MASK;
|
||||
cc >>= _DIGIT_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
dest.used = used;
|
||||
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||
clamp(dest);
|
||||
return .OK;
|
||||
}
|
||||
|
||||
/*
|
||||
2's complement `or`, returns `dest = a | b;`
|
||||
*/
|
||||
or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||
|
||||
used := max(a.used, b.used) + 1;
|
||||
neg: bool;
|
||||
|
||||
neg = is_neg(a) || is_neg(b);
|
||||
|
||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||
|
||||
/*
|
||||
Grow the destination to accomodate the result.
|
||||
*/
|
||||
if err = grow(dest, used); err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
for i := 0; i < used; i += 1 {
|
||||
x, y: DIGIT;
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if is_neg(a) {
|
||||
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||
x = ac & _MASK;
|
||||
ac >>= _DIGIT_BITS;
|
||||
} else {
|
||||
x = 0 if i >= a.used else a.digit[i];
|
||||
}
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if is_neg(a) {
|
||||
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||
y = bc & _MASK;
|
||||
bc >>= _DIGIT_BITS;
|
||||
} else {
|
||||
y = 0 if i >= b.used else b.digit[i];
|
||||
}
|
||||
|
||||
dest.digit[i] = x | y;
|
||||
|
||||
/*
|
||||
Convert to to sign-magnitude if negative.
|
||||
*/
|
||||
if neg {
|
||||
cc += ~dest.digit[i] & _MASK;
|
||||
dest.digit[i] = cc & _MASK;
|
||||
cc >>= _DIGIT_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
dest.used = used;
|
||||
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||
clamp(dest);
|
||||
return .OK;
|
||||
}
|
||||
|
||||
/*
|
||||
2's complement `xor`, returns `dest = a ~ b;`
|
||||
*/
|
||||
xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||
|
||||
used := max(a.used, b.used) + 1;
|
||||
neg: bool;
|
||||
|
||||
neg = is_neg(a) != is_neg(b);
|
||||
|
||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||
|
||||
/*
|
||||
Grow the destination to accomodate the result.
|
||||
*/
|
||||
if err = grow(dest, used); err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
for i := 0; i < used; i += 1 {
|
||||
x, y: DIGIT;
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if is_neg(a) {
|
||||
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||
x = ac & _MASK;
|
||||
ac >>= _DIGIT_BITS;
|
||||
} else {
|
||||
x = 0 if i >= a.used else a.digit[i];
|
||||
}
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if is_neg(a) {
|
||||
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||
y = bc & _MASK;
|
||||
bc >>= _DIGIT_BITS;
|
||||
} else {
|
||||
y = 0 if i >= b.used else b.digit[i];
|
||||
}
|
||||
|
||||
dest.digit[i] = x ~ y;
|
||||
|
||||
/*
|
||||
Convert to to sign-magnitude if negative.
|
||||
*/
|
||||
if neg {
|
||||
cc += ~dest.digit[i] & _MASK;
|
||||
dest.digit[i] = cc & _MASK;
|
||||
cc >>= _DIGIT_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
dest.used = used;
|
||||
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||
clamp(dest);
|
||||
return .OK;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package bigint
|
||||
package big
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
@@ -11,21 +11,20 @@ package bigint
|
||||
This file contains radix conversions, `string_to_int` (atoi) and `int_to_string` (itoa).
|
||||
*/
|
||||
|
||||
import "core:mem"
|
||||
import "core:intrinsics"
|
||||
import "core:fmt"
|
||||
import "core:strings"
|
||||
import "core:slice"
|
||||
|
||||
/*
|
||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||
*/
|
||||
itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
||||
radix := radix;
|
||||
assert_initialized(a);
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix := radix if radix > 0 else 10;
|
||||
radix = radix if radix > 0 else 10;
|
||||
|
||||
/*
|
||||
TODO: If we want to write a prefix for some of the radixes, we can oversize the buffer.
|
||||
@@ -87,11 +86,12 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
|
||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||
*/
|
||||
itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
|
||||
radix := radix;
|
||||
assert_initialized(a);
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix := radix if radix > 0 else 10;
|
||||
radix = radix if radix > 0 else 10;
|
||||
|
||||
s: string;
|
||||
s, err = itoa_string(a, radix, true, allocator);
|
||||
@@ -119,11 +119,12 @@ itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -
|
||||
and having to perform a buffer overflow check each character.
|
||||
*/
|
||||
itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
||||
radix := radix;
|
||||
assert_initialized(a); size := size;
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix := radix if radix > 0 else 10;
|
||||
radix = radix if radix > 0 else 10;
|
||||
if radix < 2 || radix > 64 {
|
||||
return 0, .Invalid_Input;
|
||||
}
|
||||
@@ -197,10 +198,10 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
|
||||
buffer[available] = 0;
|
||||
}
|
||||
|
||||
mask := _WORD(radix - 1);
|
||||
// mask := _WORD(radix - 1);
|
||||
shift := int(log_n(DIGIT(radix), 2));
|
||||
count := int(count_bits(a));
|
||||
digit: _WORD;
|
||||
// digit: _WORD;
|
||||
|
||||
for offset := 0; offset < count; offset += 4 {
|
||||
bits_to_get := int(min(count - offset, shift));
|
||||
@@ -1,3 +0,0 @@
|
||||
@echo off
|
||||
odin run .
|
||||
rem -vet
|
||||
@@ -1,113 +0,0 @@
|
||||
package bigint
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-2 license.
|
||||
|
||||
A BigInt implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
This file contains logical operations like `and`, `or` and `xor`.
|
||||
*/
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
@private
|
||||
Operator :: enum u8 {
|
||||
And = 1,
|
||||
Or = 2,
|
||||
Xor = 3,
|
||||
}
|
||||
|
||||
/*
|
||||
2's complement `and`, returns `dest = a & b;`
|
||||
*/
|
||||
|
||||
_binary_op :: proc(dest, a, b: ^Int, op: Operator) -> (err: Error) {
|
||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||
|
||||
used := max(a.used, b.used) + 1;
|
||||
neg: bool;
|
||||
|
||||
switch(op) {
|
||||
case .And:
|
||||
neg = is_neg(a) && is_neg(b);
|
||||
case .Or:
|
||||
neg = is_neg(a) || is_neg(b);
|
||||
case .Xor:
|
||||
neg = is_neg(a) != is_neg(b);
|
||||
case:
|
||||
return .Invalid_Input;
|
||||
}
|
||||
|
||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||
|
||||
/*
|
||||
Grow the destination to accomodate the result.
|
||||
*/
|
||||
if err = grow(dest, used); err != .OK {
|
||||
return err;
|
||||
}
|
||||
|
||||
for i := 0; i < used; i += 1 {
|
||||
x, y: DIGIT;
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if is_neg(a) {
|
||||
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||
x = ac & _MASK;
|
||||
ac >>= _DIGIT_BITS;
|
||||
} else {
|
||||
x = 0 if i >= a.used else a.digit[i];
|
||||
}
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if is_neg(a) {
|
||||
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||
y = bc & _MASK;
|
||||
bc >>= _DIGIT_BITS;
|
||||
} else {
|
||||
y = 0 if i >= b.used else b.digit[i];
|
||||
}
|
||||
|
||||
switch(op) {
|
||||
case .And:
|
||||
dest.digit[i] = x & y;
|
||||
case .Or:
|
||||
dest.digit[i] = x | y;
|
||||
case .Xor:
|
||||
dest.digit[i] = x ~ y;
|
||||
}
|
||||
|
||||
/*
|
||||
Convert to to sign-magnitude if negative.
|
||||
*/
|
||||
if neg {
|
||||
cc += ~dest.digit[i] & _MASK;
|
||||
dest.digit[i] = cc & _MASK;
|
||||
cc >>= _DIGIT_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
dest.used = used;
|
||||
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||
clamp(dest);
|
||||
return .OK;
|
||||
}
|
||||
|
||||
and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
return _binary_op(dest, a, b, .And);
|
||||
}
|
||||
|
||||
or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
return _binary_op(dest, a, b, .Or);
|
||||
}
|
||||
|
||||
xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
return _binary_op(dest, a, b, .Xor);
|
||||
}
|
||||
Reference in New Issue
Block a user