mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 23:28:48 +00:00
big: More refactoring.
This commit is contained in:
+42
-343
@@ -23,210 +23,48 @@ import "core:mem"
|
||||
/*
|
||||
2's complement `and`, returns `dest = a & b;`
|
||||
*/
|
||||
int_and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
if err = clear_if_uninitialized(a, b); err != nil { return err; }
|
||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
|
||||
|
||||
used := max(a.used, b.used) + 1;
|
||||
/*
|
||||
Grow the destination to accomodate the result.
|
||||
*/
|
||||
if err = grow(dest, used); err != nil { return err; }
|
||||
|
||||
neg_a, _ := is_neg(a);
|
||||
neg_b, _ := is_neg(b);
|
||||
neg := neg_a && neg_b;
|
||||
|
||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||
|
||||
for i := 0; i < used; i += 1 {
|
||||
x, y: DIGIT;
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if 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 neg_b {
|
||||
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;
|
||||
return clamp(dest);
|
||||
return #force_inline internal_int_and(dest, a, b, allocator);
|
||||
}
|
||||
and :: proc { int_add, };
|
||||
and :: proc { int_and, };
|
||||
|
||||
/*
|
||||
2's complement `or`, returns `dest = a | b;`
|
||||
*/
|
||||
int_or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
if err = clear_if_uninitialized(a, b); err != nil { return err; }
|
||||
used := max(a.used, b.used) + 1;
|
||||
/*
|
||||
Grow the destination to accomodate the result.
|
||||
*/
|
||||
if err = grow(dest, used); err != nil { return err; }
|
||||
int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
|
||||
|
||||
neg_a, _ := is_neg(a);
|
||||
neg_b, _ := is_neg(b);
|
||||
neg := neg_a || neg_b;
|
||||
|
||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||
|
||||
for i := 0; i < used; i += 1 {
|
||||
x, y: DIGIT;
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if 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 neg_b {
|
||||
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;
|
||||
return clamp(dest);
|
||||
return #force_inline internal_int_or(dest, a, b, allocator);
|
||||
}
|
||||
or :: proc { int_or, };
|
||||
|
||||
/*
|
||||
2's complement `xor`, returns `dest = a ~ b;`
|
||||
2's complement `xor`, returns `dest = a ^ b;`
|
||||
*/
|
||||
int_xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||
if err = clear_if_uninitialized(a, b); err != nil { return err; }
|
||||
int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
|
||||
|
||||
used := max(a.used, b.used) + 1;
|
||||
/*
|
||||
Grow the destination to accomodate the result.
|
||||
*/
|
||||
if err = grow(dest, used); err != nil { return err; }
|
||||
|
||||
neg_a, _ := is_neg(a);
|
||||
neg_b, _ := is_neg(b);
|
||||
neg := neg_a != neg_b;
|
||||
|
||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||
|
||||
for i := 0; i < used; i += 1 {
|
||||
x, y: DIGIT;
|
||||
|
||||
/*
|
||||
Convert to 2's complement if negative.
|
||||
*/
|
||||
if 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 neg_b {
|
||||
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;
|
||||
return clamp(dest);
|
||||
return #force_inline internal_int_xor(dest, a, b, allocator);
|
||||
}
|
||||
xor :: proc { int_xor, };
|
||||
|
||||
/*
|
||||
dest = ~src
|
||||
*/
|
||||
int_complement :: proc(dest, src: ^Int) -> (err: Error) {
|
||||
int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that src is usable. Dest will get checked by `sub`.
|
||||
Check that `src` and `dest` are usable.
|
||||
*/
|
||||
if err = clear_if_uninitialized(src); err != nil { return err; }
|
||||
assert_if_nil(dest, src);
|
||||
if err = internal_clear_if_uninitialized(dest, allocator); err != nil { return err; }
|
||||
if err = internal_clear_if_uninitialized(src, allocator); err != nil { return err; }
|
||||
|
||||
/*
|
||||
Temporarily fix sign.
|
||||
*/
|
||||
old_sign := src.sign;
|
||||
z, _ := is_zero(src);
|
||||
|
||||
src.sign = .Negative if (src.sign == .Zero_or_Positive || z) else .Zero_or_Positive;
|
||||
|
||||
err = sub(dest, src, 1);
|
||||
/*
|
||||
Restore sign.
|
||||
*/
|
||||
src.sign = old_sign;
|
||||
|
||||
return err;
|
||||
return #force_inline internal_int_complement(dest, src);
|
||||
}
|
||||
complement :: proc { int_complement, };
|
||||
|
||||
@@ -234,115 +72,43 @@ complement :: proc { int_complement, };
|
||||
quotient, remainder := numerator >> bits;
|
||||
`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.
|
||||
*/
|
||||
int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int) -> (err: Error) {
|
||||
bits := bits;
|
||||
if err = clear_if_uninitialized(quotient, numerator); err != nil { return err; }
|
||||
int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(quotient, numerator);
|
||||
if err = internal_clear_if_uninitialized(quotient, allocator); err != nil { return err; }
|
||||
if err = internal_clear_if_uninitialized(numerator, allocator); err != nil { return err; }
|
||||
|
||||
if bits < 0 { return .Invalid_Argument; }
|
||||
|
||||
if err = copy(quotient, numerator); err != nil { return err; }
|
||||
|
||||
/*
|
||||
Shift right by a certain bit count (store quotient and optional remainder.)
|
||||
`numerator` should not be used after this.
|
||||
*/
|
||||
if remainder != nil {
|
||||
if err = mod_bits(remainder, numerator, bits); err != nil { return err; }
|
||||
}
|
||||
|
||||
/*
|
||||
Shift by as many digits in the bit count.
|
||||
*/
|
||||
if bits >= _DIGIT_BITS {
|
||||
if err = shr_digit(quotient, bits / _DIGIT_BITS); err != nil { return err; }
|
||||
}
|
||||
|
||||
/*
|
||||
Shift any bit count < _DIGIT_BITS.
|
||||
*/
|
||||
bits %= _DIGIT_BITS;
|
||||
if bits != 0 {
|
||||
mask := DIGIT(1 << uint(bits)) - 1;
|
||||
shift := DIGIT(_DIGIT_BITS - bits);
|
||||
carry := DIGIT(0);
|
||||
|
||||
for x := quotient.used - 1; x >= 0; x -= 1 {
|
||||
/*
|
||||
Get the lower bits of this word in a temp.
|
||||
*/
|
||||
fwd_carry := quotient.digit[x] & mask;
|
||||
|
||||
/*
|
||||
Shift the current word and mix in the carry bits from the previous word.
|
||||
*/
|
||||
quotient.digit[x] = (quotient.digit[x] >> uint(bits)) | (carry << shift);
|
||||
|
||||
/*
|
||||
Update carry from forward carry.
|
||||
*/
|
||||
carry = fwd_carry;
|
||||
}
|
||||
|
||||
}
|
||||
return clamp(numerator);
|
||||
return #force_inline internal_int_shrmod(quotient, remainder, numerator, bits, allocator);
|
||||
}
|
||||
shrmod :: proc { int_shrmod, };
|
||||
|
||||
int_shr :: proc(dest, source: ^Int, bits: int) -> (err: Error) {
|
||||
return shrmod(dest, nil, source, bits);
|
||||
return #force_inline shrmod(dest, nil, source, bits);
|
||||
}
|
||||
shr :: proc { int_shr, };
|
||||
|
||||
/*
|
||||
Shift right by `digits` * _DIGIT_BITS bits.
|
||||
*/
|
||||
int_shr_digit :: proc(quotient: ^Int, digits: int) -> (err: Error) {
|
||||
int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `quotient` is usable.
|
||||
*/
|
||||
if err = clear_if_uninitialized(quotient); err != nil { return err; }
|
||||
assert_if_nil(quotient);
|
||||
if err = internal_clear_if_uninitialized(quotient, allocator); err != nil { return err; }
|
||||
|
||||
if digits <= 0 { return nil; }
|
||||
|
||||
/*
|
||||
If digits > used simply zero and return.
|
||||
*/
|
||||
if digits > quotient.used {
|
||||
return zero(quotient);
|
||||
}
|
||||
|
||||
/*
|
||||
Much like `int_shl_digit`, this is implemented using a sliding window,
|
||||
except the window goes the other way around.
|
||||
|
||||
b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
|
||||
/\ | ---->
|
||||
\-------------------/ ---->
|
||||
*/
|
||||
|
||||
for x := 0; x < (quotient.used - digits); x += 1 {
|
||||
quotient.digit[x] = quotient.digit[x + digits];
|
||||
}
|
||||
quotient.used -= digits;
|
||||
zero_unused(quotient);
|
||||
return clamp(quotient);
|
||||
return #force_inline internal_int_shr_digit(quotient, digits, allocator);
|
||||
}
|
||||
shr_digit :: proc { int_shr_digit, };
|
||||
|
||||
/*
|
||||
Shift right by a certain bit count with sign extension.
|
||||
*/
|
||||
int_shr_signed :: proc(dest, src: ^Int, bits: int) -> (err: Error) {
|
||||
if err = clear_if_uninitialized(src); err != nil { return err; }
|
||||
if err = clear_if_uninitialized(dest); err != nil { return err; }
|
||||
int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
if err = internal_clear_if_uninitialized(dest, allocator); err != nil { return err; }
|
||||
if err = internal_clear_if_uninitialized(src, allocator); err != nil { return err; }
|
||||
|
||||
if src.sign == .Zero_or_Positive {
|
||||
return shr(dest, src, bits);
|
||||
}
|
||||
if err = add(dest, src, DIGIT(1)); err != nil { return err; }
|
||||
|
||||
if err = shr(dest, dest, bits); err != nil { return err; }
|
||||
return sub(dest, src, DIGIT(1));
|
||||
return #force_inline internal_int_shr_signed(dest, src, bits);
|
||||
}
|
||||
|
||||
shr_signed :: proc { int_shr_signed, };
|
||||
@@ -350,53 +116,12 @@ shr_signed :: proc { int_shr_signed, };
|
||||
/*
|
||||
Shift left by a certain bit count.
|
||||
*/
|
||||
int_shl :: proc(dest, src: ^Int, bits: int) -> (err: Error) {
|
||||
bits := bits;
|
||||
if err = clear_if_uninitialized(src, dest); err != nil { return err; }
|
||||
int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
if err = internal_clear_if_uninitialized(dest, allocator); err != nil { return err; }
|
||||
if err = internal_clear_if_uninitialized(src, allocator); err != nil { return err; }
|
||||
|
||||
if bits < 0 {
|
||||
return .Invalid_Argument;
|
||||
}
|
||||
|
||||
if err = copy(dest, src); err != nil { return err; }
|
||||
|
||||
/*
|
||||
Grow `dest` to accommodate the additional bits.
|
||||
*/
|
||||
digits_needed := dest.used + (bits / _DIGIT_BITS) + 1;
|
||||
if err = grow(dest, digits_needed); err != nil { return err; }
|
||||
dest.used = digits_needed;
|
||||
/*
|
||||
Shift by as many digits in the bit count as we have.
|
||||
*/
|
||||
if bits >= _DIGIT_BITS {
|
||||
if err = shl_digit(dest, bits / _DIGIT_BITS); err != nil { return err; }
|
||||
}
|
||||
|
||||
/*
|
||||
Shift any remaining bit count < _DIGIT_BITS
|
||||
*/
|
||||
bits %= _DIGIT_BITS;
|
||||
if bits != 0 {
|
||||
mask := (DIGIT(1) << uint(bits)) - DIGIT(1);
|
||||
shift := DIGIT(_DIGIT_BITS - bits);
|
||||
carry := DIGIT(0);
|
||||
|
||||
for x:= 0; x < dest.used; x+= 1 {
|
||||
fwd_carry := (dest.digit[x] >> shift) & mask;
|
||||
dest.digit[x] = (dest.digit[x] << uint(bits) | carry) & _MASK;
|
||||
carry = fwd_carry;
|
||||
}
|
||||
|
||||
/*
|
||||
Use final carry.
|
||||
*/
|
||||
if carry != 0 {
|
||||
dest.digit[dest.used] = carry;
|
||||
dest.used += 1;
|
||||
}
|
||||
}
|
||||
return clamp(dest);
|
||||
return #force_inline internal_int_shl(dest, src, bits);
|
||||
}
|
||||
shl :: proc { int_shl, };
|
||||
|
||||
@@ -408,35 +133,9 @@ int_shl_digit :: proc(quotient: ^Int, digits: int) -> (err: Error) {
|
||||
/*
|
||||
Check that `quotient` is usable.
|
||||
*/
|
||||
if err = clear_if_uninitialized(quotient); err != nil { return err; }
|
||||
assert_if_nil(quotient);
|
||||
if err = internal_clear_if_uninitialized(quotient); err != nil { return err; }
|
||||
|
||||
if digits <= 0 { return nil; }
|
||||
|
||||
/*
|
||||
No need to shift a zero.
|
||||
*/
|
||||
z: bool;
|
||||
if z, err = is_zero(quotient); z || err != nil { return err; }
|
||||
|
||||
/*
|
||||
Resize `quotient` to accomodate extra digits.
|
||||
*/
|
||||
if err = grow(quotient, quotient.used + digits); err != nil { return err; }
|
||||
|
||||
/*
|
||||
Increment the used by the shift amount then copy upwards.
|
||||
*/
|
||||
|
||||
/*
|
||||
Much like `int_shr_digit`, this is implemented using a sliding window,
|
||||
except the window goes the other way around.
|
||||
*/
|
||||
for x := quotient.used; x > 0; x -= 1 {
|
||||
quotient.digit[x+digits-1] = quotient.digit[x-1];
|
||||
}
|
||||
|
||||
quotient.used += digits;
|
||||
mem.zero_slice(quotient.digit[:digits]);
|
||||
return nil;
|
||||
return #force_inline internal_int_shl_digit(quotient, digits);
|
||||
}
|
||||
shl_digit :: proc { int_shl_digit, };
|
||||
Reference in New Issue
Block a user