commit d474fea33792aa36fbd9fb8b4d70ead78ed5d700
parent 3ba9440d04936336f036761c59b4b82345e858e4
Author: Sebastian <sebastian@sebsite.pw>
Date: Sun, 1 Dec 2024 20:25:24 -0500
math: delete addu* and subu* functions
These were redundant with math::checked::add* and math::checked::sub*,
but with a more confusing and error-prone interface.
This is a breaking change.
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
3 files changed, 6 insertions(+), 148 deletions(-)
diff --git a/math/complex/complex.ha b/math/complex/complex.ha
@@ -55,6 +55,7 @@
// ====================================================
use math;
+use math::checked;
// A complex number containing a real component and an imaginary component,
// represented as two single-precision floating point numbers.
@@ -519,8 +520,8 @@ fn reducePi(x: f64) f64 = {
let (z2hi, z2lo) = math::mulu64(z2, ix);
let (z1hi, z1lo) = math::mulu64(z1, ix);
let z0lo: u64 = z0 * ix;
- let (lo, c) = math::addu64(z1lo, z2hi, 0);
- let (hi, _) = math::addu64(z0lo, z1hi, c);
+ let (lo, c) = checked::addu64(z1lo, z2hi);
+ let hi = z0lo + z1hi + (if (c) 1u64 else 0u64);
// Find the magnitude of the fraction.
let lz: u8 = math::leading_zeros_u64(hi);
let e: u64 = (bias - (lz + 1)): u64;
diff --git a/math/trig.ha b/math/trig.ha
@@ -174,11 +174,9 @@ fn trig_reduce(x: f64) (u64, f64) = {
const z1hi = z1.0;
const z1lo = z1.1;
const z0lo = z0 * ix;
- const add1 = addu64(z1lo, z2hi, 0);
- const lo = add1.0;
- const c = add1.1;
- const add2 = addu64(z0lo, z1hi, c);
- let hi = add2.0;
+ const lo = z1lo + z2hi;
+ let hi = z0lo + z1hi;
+ hi += (z1lo >> 63) & (z2hi >> 63); // carry from lo
// The top 3 bits are j.
let j = hi >> 61;
// Extract the fraction and find its magnitude.
diff --git a/math/uints.ha b/math/uints.ha
@@ -250,147 +250,6 @@ export fn popcount(x: u64) u8 = {
assert(popcount(~0) == 64);
};
-// Returns the sum with carry of x, y and carry: sum = x + y + carry.
-// The carry input must be 0 or 1, otherwise the behavior is undefined.
-// The carry_out output is guaranteed to be 0 or 1.
-export fn addu32(x: u32, y: u32, carry: u32) (u32, u32) = {
- const sum64 = (x: u64) + (y: u64) + (carry: u64);
- const sum = (sum64: u32);
- const carry_out = ((sum64 >> 32): u32);
- return (sum, carry_out);
-};
-
-// Returns the sum with carry of x, y and carry: sum = x + y + carry.
-// The carry input must be 0 or 1, otherwise the behavior is undefined.
-// The carry_out output is guaranteed to be 0 or 1.
-export fn addu64(x: u64, y: u64, carry: u64) (u64, u64) = {
- const sum = x + y + carry;
- // The sum will overflow if both top bits are set (x & y) or if one of
- // them is (x | y), and a carry from the lower place happened. If such a
- // carry happens, the top bit will be 1 + 0 + 1 = 0 (& ~sum).
- const carry_out = ((x & y) | ((x | y) & ~sum)) >> 63;
- return (sum, carry_out);
-};
-
-// Calls either addu32() or addu64() depending on size(uint).
-export fn addu(x: uint, y: uint, carry: uint) (uint, uint) = {
- if (size(uint) == 4) {
- const res = addu32((x: u32), (y: u32), (carry: u32));
- return ((res.0: uint), (res.1: uint));
- };
- const res = addu64((x: u64), (y: u64), (carry: u64));
- return ((res.0: uint), (res.1: uint));
-};
-
-@test fn addu() void = {
- // 32
- let res = addu32(2u32, 2u32, 0u32);
- assert(res.0 == 4u32);
- assert(res.1 == 0u32);
- let res = addu32(2u32, 2u32, 1u32);
- assert(res.0 == 5u32);
- assert(res.1 == 0u32);
- let res = addu32(~0u32, 0u32, 0u32);
- assert(res.0 == ~0u32);
- assert(res.1 == 0u32);
- let res = addu32(~0u32, 1u32, 0u32);
- assert(res.0 == 0u32);
- assert(res.1 == 1u32);
-
- // 64
- let res = addu64(2u64, 2u64, 0u64);
- assert(res.0 == 4u64);
- assert(res.1 == 0u64);
- let res = addu64(2u64, 2u64, 1u64);
- assert(res.0 == 5u64);
- assert(res.1 == 0u64);
- let res = addu64(~0u64, 0u64, 0u64);
- assert(res.0 == ~0u64);
- assert(res.1 == 0u64);
- let res = addu64(~0u64, 1u64, 0u64);
- assert(res.0 == 0u64);
- assert(res.1 == 1u64);
-
- // addu()
- let res = addu(2u, 2u, 0u);
- assert(res.0 == 4u);
- assert(res.1 == 0u);
- let res = addu(2u, 2u, 1u);
- assert(res.0 == 5u);
- assert(res.1 == 0u);
-};
-
-// Returns the difference of x, y and borrow, diff = x - y - borrow.
-// The borrow input must be 0 or 1, otherwise the behavior is undefined.
-// The borrow_out output is guaranteed to be 0 or 1.
-export fn subu32(x: u32, y: u32, borrow: u32) (u32, u32) = {
- const diff = x - y - borrow;
- // The difference will underflow if the top bit of x is not set and the
- // top bit of y is set (^x & y) or if they are the same (^(x ^ y)) and a
- // borrow from the lower place happens. If that borrow happens, the
- // result will be 1 - 1 - 1 = 0 - 0 - 1 = 1 (& diff).
- const borrow_out = ((~x & y) | (~(x ^ y) & diff)) >> 31;
- return (diff, borrow_out);
-};
-
-// Returns the difference of x, y and borrow, diff = x - y - borrow.
-// The borrow input must be 0 or 1, otherwise the behavior is undefined.
-// The borrow_out output is guaranteed to be 0 or 1.
-export fn subu64(x: u64, y: u64, borrow: u64) (u64, u64) = {
- const diff = x - y - borrow;
- // See subu32 for the bit logic.
- const borrow_out = ((~x & y) | (~(x ^ y) & diff)) >> 63;
- return (diff, borrow_out);
-};
-
-// Calls either mulu32() or mulu64() depending on size(uint).
-export fn subu(x: uint, y: uint, carry: uint) (uint, uint) = {
- if (size(uint) == 4) {
- const res = subu32((x: u32), (y: u32), (carry: u32));
- return ((res.0: uint), (res.1: uint));
- };
- const res = subu64((x: u64), (y: u64), (carry: u64));
- return ((res.0: uint), (res.1: uint));
-};
-
-@test fn subu() void = {
- // 32
- let res = subu32(4u32, 2u32, 0u32);
- assert(res.0 == 2u32);
- assert(res.1 == 0u32);
- let res = subu32(4u32, 2u32, 1u32);
- assert(res.0 == 1u32);
- assert(res.1 == 0u32);
- let res = subu32(0u32, 0u32, 0u32);
- assert(res.0 == 0u32);
- assert(res.1 == 0u32);
- let res = subu32(0u32, 1u32, 0u32);
- assert(res.0 == ~0u32);
- assert(res.1 == 1u32);
-
- // 64
- let res = subu64(4u64, 2u64, 0u64);
- assert(res.0 == 2u64);
- assert(res.1 == 0u64);
- let res = subu64(4u64, 2u64, 1u64);
- assert(res.0 == 1u64);
- assert(res.1 == 0u64);
- let res = subu64(0u64, 0u64, 0u64);
- assert(res.0 == 0u64);
- assert(res.1 == 0u64);
- let res = subu64(0u64, 1u64, 0u64);
- assert(res.0 == ~0u64);
- assert(res.1 == 1u64);
-
- // subu()
- let res = subu(4u, 2u, 0u);
- assert(res.0 == 2u);
- assert(res.1 == 0u);
- let res = subu(4u, 2u, 1u);
- assert(res.0 == 1u);
- assert(res.1 == 0u);
-};
-
// Returns the 64-bit product of x and y: (hi, lo) = x * y
// with the product bits' upper half returned in hi and the lower
// half returned in lo.