hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mmath/complex/complex.ha | 5+++--
Mmath/trig.ha | 8+++-----
Mmath/uints.ha | 141-------------------------------------------------------------------------------
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.