| ... | @@ -880,6 +880,35 @@ test "fmod, fmodf" { | ... | @@ -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 | // NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound | 912 | // NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound |
| 884 | // behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are | 913 | // behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are |
| 885 | // potentially some edge cases remaining that are not handled in the same way. | 914 | // potentially some edge cases remaining that are not handled in the same way. |