lib/math: checked sat_subu* unsigned saturating subtract (#28)
Port the deferred sat_subu8/16/32/64 from ref/hare/math/checked/saturating.ha:196,206,216,226 — clamp to types.U*_MIN (0) on underflow. Mirrors the existing sat_addu* shape (typed res forces the sub-word wrap, then the >a underflow test). Tests: sat_subu* normal+clamp rows plus a direct types min check (U*_MIN==0, RUNE_MIN=='\0'), wired into checked_test main().
This commit is contained in:
@@ -302,6 +302,37 @@ import types;
|
||||
if (checked.sat_subi64(9223372036854775800, -10) != types.I64_MAX) { let _: i32 = 1/0; };
|
||||
};
|
||||
|
||||
// The third/fourth rows of each sat_subu* test go beyond Hare's two
|
||||
// vectors: a==b (exact-zero, non-saturating edge) and 0−U*_MAX (extreme
|
||||
// operand forcing the deepest underflow). #28 reviewer hardening.
|
||||
@test fn test_sat_subu8() void = {
|
||||
if (checked.sat_subu8(250u8, 50u8) != 200u8) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu8(44u8, 100u8) != types.U8_MIN) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu8(100u8, 100u8) != 0u8) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu8(0u8, 255u8) != types.U8_MIN) { let _: i32 = 1/0; };
|
||||
};
|
||||
|
||||
@test fn test_sat_subu16() void = {
|
||||
if (checked.sat_subu16(65530u16, 30u16) != 65500u16) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu16(14u16, 50u16) != types.U16_MIN) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu16(1000u16, 1000u16) != 0u16) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu16(0u16, 65535u16) != types.U16_MIN) { let _: i32 = 1/0; };
|
||||
};
|
||||
|
||||
@test fn test_sat_subu32() void = {
|
||||
if (checked.sat_subu32(4294967290u32, 90u32) != 4294967200u32) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu32(4u32, 100u32) != types.U32_MIN) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu32(1000000u32, 1000000u32) != 0u32) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu32(0u32, 4294967295u32) != types.U32_MIN) { let _: i32 = 1/0; };
|
||||
};
|
||||
|
||||
@test fn test_sat_subu64() void = {
|
||||
if (checked.sat_subu64(18446744073709551610u64, 10u64) != 18446744073709551600u64) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu64(44u64, 50u64) != types.U64_MIN) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu64(1000000u64, 1000000u64) != 0u64) { let _: i32 = 1/0; };
|
||||
if (checked.sat_subu64(0u64, 18446744073709551615u64) != types.U64_MIN) { let _: i32 = 1/0; };
|
||||
};
|
||||
|
||||
@test fn test_sat_muli8() void = {
|
||||
if (checked.sat_muli8(11, 11) != 121) { let _: i32 = 1/0; };
|
||||
if (checked.sat_muli8(12, 12) != types.I8_MAX) { let _: i32 = 1/0; };
|
||||
@@ -341,6 +372,18 @@ import types;
|
||||
if (checked.sat_mulu32(65536u32, 65536u32) != types.U32_MAX) { let _: i32 = 1/0; };
|
||||
};
|
||||
|
||||
// Direct read of types::U*_MIN (all 0, ref/hare/types/limits.ha:30,36,
|
||||
// 42,48) and RUNE_MIN ('\0', :54). The sat_subu* clamp cases above also
|
||||
// exercise the U*_MIN, but assert the bare values here so a regression in
|
||||
// lib/types surfaces standalone.
|
||||
@test fn test_types_min() void = {
|
||||
if (types.U8_MIN != 0u8) { let _: i32 = 1/0; };
|
||||
if (types.U16_MIN != 0u16) { let _: i32 = 1/0; };
|
||||
if (types.U32_MIN != 0u32) { let _: i32 = 1/0; };
|
||||
if (types.U64_MIN != 0u64) { let _: i32 = 1/0; };
|
||||
if (types.RUNE_MIN != '\0') { let _: i32 = 1/0; };
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
test_addi8();
|
||||
test_addi16();
|
||||
@@ -376,11 +419,16 @@ export fn main() i32 = {
|
||||
test_sat_subi16();
|
||||
test_sat_subi32();
|
||||
test_sat_subi64();
|
||||
test_sat_subu8();
|
||||
test_sat_subu16();
|
||||
test_sat_subu32();
|
||||
test_sat_subu64();
|
||||
test_sat_muli8();
|
||||
test_sat_muli16();
|
||||
test_sat_muli32();
|
||||
test_sat_mulu8();
|
||||
test_sat_mulu16();
|
||||
test_sat_mulu32();
|
||||
test_types_min();
|
||||
return 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user