hare

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

commit 127f2ed3dcebf899067b15a4de248860f99ae72d
parent a1c5abf4e635079f49a468f4a7bf4b49390cfdbb
Author: Sebastian <sebastian@sebsite.pw>
Date:   Sun,  1 Dec 2024 20:25:15 -0500

math::checked: add functions for int, uint, and size

Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Mmath/checked/checked.ha | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmath/checked/saturating.ha | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 140 insertions(+), 0 deletions(-)

diff --git a/math/checked/checked.ha b/math/checked/checked.ha @@ -69,6 +69,13 @@ export fn addi64(a: i64, b: i64) (i64, bool) = { }; // Adds 'a' and 'b', returning the result and whether overflow occurred. +export fn addi(a: int, b: int) (int, bool) = { + const res = a + b; + const overflow = a < 0 == b < 0 && a < 0 != res < 0; + return (res, overflow); +}; + +// Adds 'a' and 'b', returning the result and whether overflow occurred. export fn addu8(a: u8, b: u8) (u8, bool) = { const res = a + b; const overflow = res < a; @@ -132,6 +139,20 @@ export fn addu64(a: u64, b: u64) (u64, bool) = { assert(overflow); }; +// Adds 'a' and 'b', returning the result and whether overflow occurred. +export fn addu(a: uint, b: uint) (uint, bool) = { + const res = a + b; + const overflow = res < a; + return (res, overflow); +}; + +// Adds 'a' and 'b', returning the result and whether overflow occurred. +export fn addz(a: size, b: size) (size, bool) = { + const res = a + b; + const overflow = res < a; + return (res, overflow); +}; + // Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subi8(a: i8, b: i8) (i8, bool) = { const res = a - b; @@ -209,6 +230,13 @@ export fn subi64(a: i64, b: i64) (i64, bool) = { }; // Subtracts 'b' from 'a', returning the result and whether overflow occurred. +export fn subi(a: int, b: int) (int, bool) = { + const res = a - b; + const overflow = a < 0 != b < 0 && a < 0 != res < 0; + return (res, overflow); +}; + +// Subtracts 'b' from 'a', returning the result and whether overflow occurred. export fn subu8(a: u8, b: u8) (u8, bool) = { const res = a - b; const overflow = res > a; @@ -272,6 +300,20 @@ export fn subu64(a: u64, b: u64) (u64, bool) = { assert(overflow); }; +// Subtracts 'b' from 'a', returning the result and whether overflow occurred. +export fn subu(a: uint, b: uint) (uint, bool) = { + const res = a - b; + const overflow = res > a; + return (res, overflow); +}; + +// Subtracts 'b' from 'a', returning the result and whether overflow occurred. +export fn subz(a: size, b: size) (size, bool) = { + const res = a - b; + const overflow = res > a; + return (res, overflow); +}; + // Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn muli8(a: i8, b: i8) (i8, bool) = { const fullres = a: int * b: int; @@ -341,6 +383,17 @@ export fn muli64(a: i64, b: i64) (i64, bool) = { }; // Multiplies 'a' and 'b' returning the result and whether overflow occurred. +export fn muli(a: int, b: int) (int, bool) = { + if (size(int) == 4) { + const ret = muli32(a: i32, b: i32); + return (ret.0, ret.1); + } else { + const ret = muli64(a, b); + return (ret.0: int, ret.1); + }; +}; + +// Multiplies 'a' and 'b' returning the result and whether overflow occurred. export fn mulu8(a: u8, b: u8) (u8, bool) = { const fullres = a: uint * b: uint; const res = fullres: u8; @@ -407,3 +460,25 @@ export fn mulu64(a: u64, b: u64) (u64, bool) = { assert(res == 0); assert(overflow); }; + +// Multiplies 'a' and 'b' returning the result and whether overflow occurred. +export fn mulu(a: uint, b: uint) (uint, bool) = { + if (size(uint) == 4) { + const ret = mulu32(a: u32, b: u32); + return (ret.0, ret.1); + } else { + const ret = mulu64(a, b); + return (ret.0: uint, ret.1); + }; +}; + +// Multiplies 'a' and 'b' returning the result and whether overflow occurred. +export fn mulz(a: size, b: size) (size, bool) = { + if (size(size) == 4) { + const ret = mulu32(a: u32, b: u32); + return (ret.0, ret.1); + } else { + const ret = mulu64(a, b); + return (ret.0: size, ret.1); + }; +}; diff --git a/math/checked/saturating.ha b/math/checked/saturating.ha @@ -65,6 +65,15 @@ export fn sat_addi64(a: i64, b: i64) i64 = { }; // Computes the saturating addition of 'a' and 'b'. +export fn sat_addi(a: int, b: int) int = { + const res = a + b; + if (a < 0 == b < 0 && a < 0 != res < 0) { + return if (res < 0) types::INT_MAX else types::INT_MIN; + }; + return res; +}; + +// Computes the saturating addition of 'a' and 'b'. export fn sat_addu8(a: u8, b: u8) u8 = { return if (a + b < a) types::U8_MAX else a + b; }; @@ -104,6 +113,16 @@ export fn sat_addu64(a: u64, b: u64) u64 = { assert(sat_addu64(18446744073709551600, 50) == types::U64_MAX); }; +// Computes the saturating addition of 'a' and 'b'. +export fn sat_addu(a: uint, b: uint) uint = { + return if (a + b < a) types::UINT_MAX else a + b; +}; + +// Computes the saturating addition of 'a' and 'b'. +export fn sat_addz(a: size, b: size) size = { + return if (a + b < a) types::SIZE_MAX else a + b; +}; + // Computes the saturating subtraction of 'b' from 'a'. export fn sat_subi8(a: i8, b: i8) i8 = { const res = a - b; @@ -165,6 +184,15 @@ export fn sat_subi64(a: i64, b: i64) i64 = { }; // Computes the saturating subtraction of 'b' from 'a'. +export fn sat_subi(a: int, b: int) int = { + const res = a - b; + if (a < 0 != b < 0 && a < 0 != res < 0) { + return if (res < 0) types::INT_MAX else types::INT_MIN; + }; + return res; +}; + +// Computes the saturating subtraction of 'b' from 'a'. export fn sat_subu8(a: u8, b: u8) u8 = { return if (a - b > a) types::U8_MIN else a - b; }; @@ -204,6 +232,16 @@ export fn sat_subu64(a: u64, b: u64) u64 = { assert(sat_subu64(44, 50) == types::U64_MIN); }; +// Computes the saturating subtraction of 'b' from 'a'. +export fn sat_subu(a: uint, b: uint) uint = { + return if (a - b > a) types::UINT_MIN else a - b; +}; + +// Computes the saturating subtraction of 'b' from 'a'. +export fn sat_subz(a: size, b: size) size = { + return if (a - b > a) types::SIZE_MIN else a - b; +}; + // Computes the saturating multiplication of 'a' and 'b'. export fn sat_muli8(a: i8, b: i8) i8 = { const fullres = a: int * b: int; @@ -276,6 +314,15 @@ export fn sat_muli64(a: i64, b: i64) i64 = { }; // Computes the saturating multiplication of 'a' and 'b'. +export fn sat_muli(a: int, b: int) int = { + if (size(int) == 4) { + return sat_muli32(a: i32, b: i32); + } else { + return sat_muli64(a, b): int; + }; +}; + +// Computes the saturating multiplication of 'a' and 'b'. export fn sat_mulu8(a: u8, b: u8) u8 = { const res = a: uint * b: uint; return if (res > types::U8_MAX) types::U8_MAX else res: u8; @@ -318,3 +365,21 @@ export fn sat_mulu64(a: u64, b: u64) u64 = { assert(sat_mulu64(4294967295, 4294967295) == 18446744065119617025); assert(sat_mulu64(4294967296, 4294967296) == types::U64_MAX); }; + +// Computes the saturating multiplication of 'a' and 'b'. +export fn sat_mulu(a: uint, b: uint) uint = { + if (size(uint) == 4) { + return sat_mulu32(a: u32, b: u32); + } else { + return sat_mulu64(a, b): uint; + }; +}; + +// Computes the saturating multiplication of 'a' and 'b'. +export fn sat_mulz(a: size, b: size) size = { + if (size(size) == 4) { + return sat_mulu32(a: u32, b: u32); + } else { + return sat_mulu64(a, b): size; + }; +};