Skip to content

Commit 9de3bea

Browse files
author
bench
committed
feat: add wasm float min, max, and nearest operations with comprehensive tests
1 parent 077e1b2 commit 9de3bea

1 file changed

Lines changed: 347 additions & 0 deletions

File tree

  • crates/herkos-runtime/src

crates/herkos-runtime/src/ops.rs

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,4 +716,351 @@ mod tests {
716716
fn i64_rem_u_zero_divisor() {
717717
assert_eq!(i64_rem_u(5, 0), Err(WasmTrap::DivisionByZero));
718718
}
719+
720+
// ── wasm_min_f32 ─────────────────────────────────────────────────────────
721+
722+
#[test]
723+
fn wasm_min_f32_normal() {
724+
assert_eq!(wasm_min_f32(3.0, 5.0), 3.0);
725+
assert_eq!(wasm_min_f32(5.0, 3.0), 3.0);
726+
}
727+
728+
#[test]
729+
fn wasm_min_f32_equal() {
730+
assert_eq!(wasm_min_f32(2.5, 2.5), 2.5);
731+
}
732+
733+
#[test]
734+
fn wasm_min_f32_nan_left() {
735+
assert!(wasm_min_f32(f32::NAN, 5.0).is_nan());
736+
}
737+
738+
#[test]
739+
fn wasm_min_f32_nan_right() {
740+
assert!(wasm_min_f32(5.0, f32::NAN).is_nan());
741+
}
742+
743+
#[test]
744+
fn wasm_min_f32_both_nan() {
745+
assert!(wasm_min_f32(f32::NAN, f32::NAN).is_nan());
746+
}
747+
748+
#[test]
749+
fn wasm_min_f32_neg_zero_pos_zero() {
750+
// min(-0.0, +0.0) should return -0.0
751+
let result = wasm_min_f32(-0.0, 0.0);
752+
assert_eq!(result, 0.0);
753+
assert!(result.is_sign_negative());
754+
}
755+
756+
#[test]
757+
fn wasm_min_f32_pos_zero_neg_zero() {
758+
// min(+0.0, -0.0) should return -0.0
759+
let result = wasm_min_f32(0.0, -0.0);
760+
assert_eq!(result, 0.0);
761+
assert!(result.is_sign_negative());
762+
}
763+
764+
#[test]
765+
fn wasm_min_f32_infinity() {
766+
assert_eq!(wasm_min_f32(f32::INFINITY, 100.0), 100.0);
767+
assert_eq!(wasm_min_f32(100.0, f32::INFINITY), 100.0);
768+
}
769+
770+
#[test]
771+
fn wasm_min_f32_neg_infinity() {
772+
assert_eq!(wasm_min_f32(f32::NEG_INFINITY, 100.0), f32::NEG_INFINITY);
773+
assert_eq!(wasm_min_f32(100.0, f32::NEG_INFINITY), f32::NEG_INFINITY);
774+
}
775+
776+
// ── wasm_max_f32 ─────────────────────────────────────────────────────────
777+
778+
#[test]
779+
fn wasm_max_f32_normal() {
780+
assert_eq!(wasm_max_f32(3.0, 5.0), 5.0);
781+
assert_eq!(wasm_max_f32(5.0, 3.0), 5.0);
782+
}
783+
784+
#[test]
785+
fn wasm_max_f32_equal() {
786+
assert_eq!(wasm_max_f32(2.5, 2.5), 2.5);
787+
}
788+
789+
#[test]
790+
fn wasm_max_f32_nan_left() {
791+
assert!(wasm_max_f32(f32::NAN, 5.0).is_nan());
792+
}
793+
794+
#[test]
795+
fn wasm_max_f32_nan_right() {
796+
assert!(wasm_max_f32(5.0, f32::NAN).is_nan());
797+
}
798+
799+
#[test]
800+
fn wasm_max_f32_neg_zero_pos_zero() {
801+
// max(-0.0, +0.0) should return +0.0
802+
let result = wasm_max_f32(-0.0, 0.0);
803+
assert_eq!(result, 0.0);
804+
assert!(result.is_sign_positive());
805+
}
806+
807+
#[test]
808+
fn wasm_max_f32_pos_zero_neg_zero() {
809+
// max(+0.0, -0.0) should return +0.0
810+
let result = wasm_max_f32(0.0, -0.0);
811+
assert_eq!(result, 0.0);
812+
assert!(result.is_sign_positive());
813+
}
814+
815+
#[test]
816+
fn wasm_max_f32_infinity() {
817+
assert_eq!(wasm_max_f32(f32::INFINITY, 100.0), f32::INFINITY);
818+
assert_eq!(wasm_max_f32(100.0, f32::INFINITY), f32::INFINITY);
819+
}
820+
821+
#[test]
822+
fn wasm_max_f32_neg_infinity() {
823+
assert_eq!(wasm_max_f32(f32::NEG_INFINITY, 100.0), 100.0);
824+
assert_eq!(wasm_max_f32(100.0, f32::NEG_INFINITY), 100.0);
825+
}
826+
827+
// ── wasm_min_f64 ─────────────────────────────────────────────────────────
828+
829+
#[test]
830+
fn wasm_min_f64_normal() {
831+
assert_eq!(wasm_min_f64(3.0, 5.0), 3.0);
832+
assert_eq!(wasm_min_f64(5.0, 3.0), 3.0);
833+
}
834+
835+
#[test]
836+
fn wasm_min_f64_equal() {
837+
assert_eq!(wasm_min_f64(2.5, 2.5), 2.5);
838+
}
839+
840+
#[test]
841+
fn wasm_min_f64_nan_left() {
842+
assert!(wasm_min_f64(f64::NAN, 5.0).is_nan());
843+
}
844+
845+
#[test]
846+
fn wasm_min_f64_nan_right() {
847+
assert!(wasm_min_f64(5.0, f64::NAN).is_nan());
848+
}
849+
850+
#[test]
851+
fn wasm_min_f64_both_nan() {
852+
assert!(wasm_min_f64(f64::NAN, f64::NAN).is_nan());
853+
}
854+
855+
#[test]
856+
fn wasm_min_f64_neg_zero_pos_zero() {
857+
// min(-0.0, +0.0) should return -0.0
858+
let result = wasm_min_f64(-0.0, 0.0);
859+
assert_eq!(result, 0.0);
860+
assert!(result.is_sign_negative());
861+
}
862+
863+
#[test]
864+
fn wasm_min_f64_pos_zero_neg_zero() {
865+
// min(+0.0, -0.0) should return -0.0
866+
let result = wasm_min_f64(0.0, -0.0);
867+
assert_eq!(result, 0.0);
868+
assert!(result.is_sign_negative());
869+
}
870+
871+
// ── wasm_max_f64 ─────────────────────────────────────────────────────────
872+
873+
#[test]
874+
fn wasm_max_f64_normal() {
875+
assert_eq!(wasm_max_f64(3.0, 5.0), 5.0);
876+
assert_eq!(wasm_max_f64(5.0, 3.0), 5.0);
877+
}
878+
879+
#[test]
880+
fn wasm_max_f64_equal() {
881+
assert_eq!(wasm_max_f64(2.5, 2.5), 2.5);
882+
}
883+
884+
#[test]
885+
fn wasm_max_f64_nan_left() {
886+
assert!(wasm_max_f64(f64::NAN, 5.0).is_nan());
887+
}
888+
889+
#[test]
890+
fn wasm_max_f64_nan_right() {
891+
assert!(wasm_max_f64(5.0, f64::NAN).is_nan());
892+
}
893+
894+
#[test]
895+
fn wasm_max_f64_neg_zero_pos_zero() {
896+
// max(-0.0, +0.0) should return +0.0
897+
let result = wasm_max_f64(-0.0, 0.0);
898+
assert_eq!(result, 0.0);
899+
assert!(result.is_sign_positive());
900+
}
901+
902+
#[test]
903+
fn wasm_max_f64_pos_zero_neg_zero() {
904+
// max(+0.0, -0.0) should return +0.0
905+
let result = wasm_max_f64(0.0, -0.0);
906+
assert_eq!(result, 0.0);
907+
assert!(result.is_sign_positive());
908+
}
909+
910+
// ── wasm_nearest_f32 ─────────────────────────────────────────────────────
911+
912+
#[test]
913+
fn wasm_nearest_f32_integer() {
914+
assert_eq!(wasm_nearest_f32(5.0), 5.0);
915+
assert_eq!(wasm_nearest_f32(-3.0), -3.0);
916+
}
917+
918+
#[test]
919+
fn wasm_nearest_f32_round_up() {
920+
// 2.7 rounds to 3.0 (frac = 0.7 > 0.5)
921+
assert_eq!(wasm_nearest_f32(2.7), 3.0);
922+
}
923+
924+
#[test]
925+
fn wasm_nearest_f32_round_down() {
926+
// 2.2 rounds to 2.0 (frac = 0.2 < 0.5)
927+
assert_eq!(wasm_nearest_f32(2.2), 2.0);
928+
}
929+
930+
#[test]
931+
fn wasm_nearest_f32_tie_round_to_even_down() {
932+
// 2.5: trunc_i = 2 (even), so round toward zero to 2
933+
assert_eq!(wasm_nearest_f32(2.5), 2.0);
934+
}
935+
936+
#[test]
937+
fn wasm_nearest_f32_tie_round_to_even_up() {
938+
// 3.5: trunc_i = 3 (odd), so round away from zero to 4 (even)
939+
assert_eq!(wasm_nearest_f32(3.5), 4.0);
940+
}
941+
942+
#[test]
943+
fn wasm_nearest_f32_negative_round_up() {
944+
// -2.7: frac = -0.7 < -0.5, so round toward zero is -2, away is -3
945+
// frac < -0.5 means round down (toward -inf) → -3
946+
assert_eq!(wasm_nearest_f32(-2.7), -3.0);
947+
}
948+
949+
#[test]
950+
fn wasm_nearest_f32_negative_round_down() {
951+
// -2.2: frac = -0.2 > -0.5, so stays at -2
952+
assert_eq!(wasm_nearest_f32(-2.2), -2.0);
953+
}
954+
955+
#[test]
956+
fn wasm_nearest_f32_negative_tie_round_to_even() {
957+
// -2.5: trunc_i = -2 (even), so round toward zero → -2.0
958+
let result = wasm_nearest_f32(-2.5);
959+
assert_eq!(result, -2.0);
960+
// Verify sign is preserved
961+
assert!(result.is_sign_negative() || result == 0.0);
962+
}
963+
964+
#[test]
965+
fn wasm_nearest_f32_nan() {
966+
assert!(wasm_nearest_f32(f32::NAN).is_nan());
967+
}
968+
969+
#[test]
970+
fn wasm_nearest_f32_infinity() {
971+
assert_eq!(wasm_nearest_f32(f32::INFINITY), f32::INFINITY);
972+
assert_eq!(wasm_nearest_f32(f32::NEG_INFINITY), f32::NEG_INFINITY);
973+
}
974+
975+
#[test]
976+
fn wasm_nearest_f32_zero() {
977+
assert_eq!(wasm_nearest_f32(0.0), 0.0);
978+
assert_eq!(wasm_nearest_f32(-0.0), -0.0);
979+
}
980+
981+
#[test]
982+
fn wasm_nearest_f32_large_no_frac() {
983+
// Values >= 2^23 have no fractional bits
984+
let large = 8_388_608.0f32; // 2^23
985+
assert_eq!(wasm_nearest_f32(large), large);
986+
assert_eq!(wasm_nearest_f32(large + 1.0), large + 1.0);
987+
}
988+
989+
// ── wasm_nearest_f64 ─────────────────────────────────────────────────────
990+
991+
#[test]
992+
fn wasm_nearest_f64_integer() {
993+
assert_eq!(wasm_nearest_f64(5.0), 5.0);
994+
assert_eq!(wasm_nearest_f64(-3.0), -3.0);
995+
}
996+
997+
#[test]
998+
fn wasm_nearest_f64_round_up() {
999+
// 2.7 rounds to 3.0
1000+
assert_eq!(wasm_nearest_f64(2.7), 3.0);
1001+
}
1002+
1003+
#[test]
1004+
fn wasm_nearest_f64_round_down() {
1005+
// 2.2 rounds to 2.0
1006+
assert_eq!(wasm_nearest_f64(2.2), 2.0);
1007+
}
1008+
1009+
#[test]
1010+
fn wasm_nearest_f64_tie_round_to_even_down() {
1011+
// 2.5: trunc_i = 2 (even), so round toward zero to 2
1012+
assert_eq!(wasm_nearest_f64(2.5), 2.0);
1013+
}
1014+
1015+
#[test]
1016+
fn wasm_nearest_f64_tie_round_to_even_up() {
1017+
// 3.5: trunc_i = 3 (odd), so round away from zero to 4 (even)
1018+
assert_eq!(wasm_nearest_f64(3.5), 4.0);
1019+
}
1020+
1021+
#[test]
1022+
fn wasm_nearest_f64_negative_round_up() {
1023+
// -2.7: frac = -0.7 < -0.5, rounds down (toward -inf) → -3
1024+
assert_eq!(wasm_nearest_f64(-2.7), -3.0);
1025+
}
1026+
1027+
#[test]
1028+
fn wasm_nearest_f64_negative_round_down() {
1029+
// -2.2: frac = -0.2 > -0.5, rounds to -2
1030+
assert_eq!(wasm_nearest_f64(-2.2), -2.0);
1031+
}
1032+
1033+
#[test]
1034+
fn wasm_nearest_f64_negative_tie_round_to_even() {
1035+
// -2.5: trunc_i = -2 (even), round toward zero → -2.0
1036+
let result = wasm_nearest_f64(-2.5);
1037+
assert_eq!(result, -2.0);
1038+
// Verify sign is preserved (or -0.0)
1039+
assert!(result.is_sign_negative() || result == 0.0);
1040+
}
1041+
1042+
#[test]
1043+
fn wasm_nearest_f64_nan() {
1044+
assert!(wasm_nearest_f64(f64::NAN).is_nan());
1045+
}
1046+
1047+
#[test]
1048+
fn wasm_nearest_f64_infinity() {
1049+
assert_eq!(wasm_nearest_f64(f64::INFINITY), f64::INFINITY);
1050+
assert_eq!(wasm_nearest_f64(f64::NEG_INFINITY), f64::NEG_INFINITY);
1051+
}
1052+
1053+
#[test]
1054+
fn wasm_nearest_f64_zero() {
1055+
assert_eq!(wasm_nearest_f64(0.0), 0.0);
1056+
assert_eq!(wasm_nearest_f64(-0.0), -0.0);
1057+
}
1058+
1059+
#[test]
1060+
fn wasm_nearest_f64_large_no_frac() {
1061+
// Values >= 2^52 have no fractional bits
1062+
let large = 4_503_599_627_370_496.0f64; // 2^52
1063+
assert_eq!(wasm_nearest_f64(large), large);
1064+
assert_eq!(wasm_nearest_f64(large + 1.0), large + 1.0);
1065+
}
7191066
}

0 commit comments

Comments
 (0)