| ... | ... | @@ -880,6 +880,35 @@ test "fmod, fmodf" { |
| 880 | 880 | } |
| 881 | 881 | } |
| 882 | 882 | |
| 883 | fn generic_fmin(comptime T: type, x: T, y: T) T { |
| 884 | if (isNan(x)) |
| 885 | return y; |
| 886 | if (isNan(y)) |
| 887 | return x; |
| 888 | return if (x < y) x else y; |
| 889 | } |
| 890 | |
| 891 | export fn fminf(x: f32, y: f32) callconv(.C) f32 { |
| 892 | return generic_fmin(f32, x, y); |
| 893 | } |
| 894 | |
| 895 | export fn fmin(x: f64, y: f64) callconv(.C) f64 { |
| 896 | return generic_fmin(f64, x, y); |
| 897 | } |
| 898 | |
| 899 | test "fmin, fminf" { |
| 900 | inline for ([_]type{ f32, f64 }) |T| { |
| 901 | const nan_val = math.nan(T); |
| 902 | |
| 903 | std.testing.expect(isNan(generic_fmin(T, nan_val, nan_val))); |
| 904 | std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, nan_val, 1.0)); |
| 905 | std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, nan_val)); |
| 906 | |
| 907 | std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, 10.0)); |
| 908 | std.testing.expectEqual(@as(T, -1.0), generic_fmin(T, 1.0, -1.0)); |
| 909 | } |
| 910 | } |
| 911 | |
| 883 | 912 | // NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound |
| 884 | 913 | // behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are |
| 885 | 914 | // potentially some edge cases remaining that are not handled in the same way. |