diff --git a/crates/libm-macros/src/shared.rs b/crates/libm-macros/src/shared.rs index b233e34f1..fbe0702a6 100644 --- a/crates/libm-macros/src/shared.rs +++ b/crates/libm-macros/src/shared.rs @@ -47,7 +47,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] }, None, - &["copysignf16", "fdimf16"], + &["copysignf16", "fdimf16", "fmaxf16", "fminf16"], ), ( // `(f32, f32) -> f32` @@ -90,7 +90,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] }, None, - &["copysignf128", "fdimf128"], + &["copysignf128", "fdimf128", "fmaxf128", "fminf128"], ), ( // `(f32, f32, f32) -> f32` diff --git a/crates/libm-test/benches/random.rs b/crates/libm-test/benches/random.rs index d0ecd851e..aac8379fd 100644 --- a/crates/libm-test/benches/random.rs +++ b/crates/libm-test/benches/random.rs @@ -127,6 +127,10 @@ libm_macros::for_each_function! { | fdimf16 | floorf128 | floorf16 + | fmaxf128 + | fmaxf16 + | fminf128 + | fminf16 | rintf128 | rintf16 | roundf128 diff --git a/crates/libm-test/src/mpfloat.rs b/crates/libm-test/src/mpfloat.rs index 4422ab88d..da674c162 100644 --- a/crates/libm-test/src/mpfloat.rs +++ b/crates/libm-test/src/mpfloat.rs @@ -192,8 +192,8 @@ libm_macros::for_each_function! { fabs | fabsf => abs, fdim | fdimf | fdimf16 | fdimf128 => positive_diff, fma | fmaf => mul_add, - fmax | fmaxf => max, - fmin | fminf => min, + fmax | fmaxf | fmaxf16 | fmaxf128 => max, + fmin | fminf | fminf16 | fminf128 => min, lgamma | lgammaf => ln_gamma, log | logf => ln, log1p | log1pf => ln_1p, diff --git a/crates/libm-test/tests/compare_built_musl.rs b/crates/libm-test/tests/compare_built_musl.rs index 0fc1b0df1..ca070e8f6 100644 --- a/crates/libm-test/tests/compare_built_musl.rs +++ b/crates/libm-test/tests/compare_built_musl.rs @@ -89,6 +89,10 @@ libm_macros::for_each_function! { fdimf16, floorf128, floorf16, + fmaxf128, + fmaxf16, + fminf128, + fminf16, rintf128, rintf16, roundf128, diff --git a/crates/util/src/main.rs b/crates/util/src/main.rs index aaedda6d1..eb8e37589 100644 --- a/crates/util/src/main.rs +++ b/crates/util/src/main.rs @@ -96,6 +96,10 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fdimf16 | floorf128 | floorf16 + | fmaxf128 + | fmaxf16 + | fminf128 + | fminf16 | rintf128 | rintf16 | roundf128 diff --git a/etc/function-definitions.json b/etc/function-definitions.json index 8c5903e93..b6653295c 100644 --- a/etc/function-definitions.json +++ b/etc/function-definitions.json @@ -379,29 +379,61 @@ "fmax": { "sources": [ "src/libm_helper.rs", - "src/math/fmax.rs" + "src/math/fmax.rs", + "src/math/generic/fmax.rs" ], "type": "f64" }, "fmaxf": { "sources": [ - "src/math/fmaxf.rs" + "src/math/fmaxf.rs", + "src/math/generic/fmax.rs" ], "type": "f32" }, + "fmaxf128": { + "sources": [ + "src/math/fmaxf128.rs", + "src/math/generic/fmax.rs" + ], + "type": "f128" + }, + "fmaxf16": { + "sources": [ + "src/math/fmaxf16.rs", + "src/math/generic/fmax.rs" + ], + "type": "f16" + }, "fmin": { "sources": [ "src/libm_helper.rs", - "src/math/fmin.rs" + "src/math/fmin.rs", + "src/math/generic/fmin.rs" ], "type": "f64" }, "fminf": { "sources": [ - "src/math/fminf.rs" + "src/math/fminf.rs", + "src/math/generic/fmin.rs" ], "type": "f32" }, + "fminf128": { + "sources": [ + "src/math/fminf128.rs", + "src/math/generic/fmin.rs" + ], + "type": "f128" + }, + "fminf16": { + "sources": [ + "src/math/fminf16.rs", + "src/math/generic/fmin.rs" + ], + "type": "f16" + }, "fmod": { "sources": [ "src/libm_helper.rs", diff --git a/etc/function-list.txt b/etc/function-list.txt index 0b6eed828..25b92e58b 100644 --- a/etc/function-list.txt +++ b/etc/function-list.txt @@ -55,8 +55,12 @@ fma fmaf fmax fmaxf +fmaxf128 +fmaxf16 fmin fminf +fminf128 +fminf16 fmod fmodf frexp diff --git a/src/math/fmax.rs b/src/math/fmax.rs index 93c97bc61..d5d9b513b 100644 --- a/src/math/fmax.rs +++ b/src/math/fmax.rs @@ -1,12 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmax(x: f64, y: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 + super::generic::fmax(x, y) } diff --git a/src/math/fmaxf.rs b/src/math/fmaxf.rs index 607746647..3197d5cf2 100644 --- a/src/math/fmaxf.rs +++ b/src/math/fmaxf.rs @@ -1,12 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmaxf(x: f32, y: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if x.is_nan() || x < y { y } else { x }) * 1.0 + super::generic::fmax(x, y) } diff --git a/src/math/fmaxf128.rs b/src/math/fmaxf128.rs new file mode 100644 index 000000000..bace9ab53 --- /dev/null +++ b/src/math/fmaxf128.rs @@ -0,0 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf128(x: f128, y: f128) -> f128 { + super::generic::fmax(x, y) +} diff --git a/src/math/fmaxf16.rs b/src/math/fmaxf16.rs new file mode 100644 index 000000000..fea15be8f --- /dev/null +++ b/src/math/fmaxf16.rs @@ -0,0 +1,5 @@ +/// Return the greater of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmaxf16(x: f16, y: f16) -> f16 { + super::generic::fmax(x, y) +} diff --git a/src/math/fmin.rs b/src/math/fmin.rs index ab1509f34..df8ff7c32 100644 --- a/src/math/fmin.rs +++ b/src/math/fmin.rs @@ -1,12 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fmin(x: f64, y: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 + super::generic::fmin(x, y) } diff --git a/src/math/fminf.rs b/src/math/fminf.rs index 0049e7117..b2cdfe89d 100644 --- a/src/math/fminf.rs +++ b/src/math/fminf.rs @@ -1,12 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn fminf(x: f32, y: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if y.is_nan() || x < y { x } else { y }) * 1.0 + super::generic::fmin(x, y) } diff --git a/src/math/fminf128.rs b/src/math/fminf128.rs new file mode 100644 index 000000000..a9224c22a --- /dev/null +++ b/src/math/fminf128.rs @@ -0,0 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf128(x: f128, y: f128) -> f128 { + super::generic::fmin(x, y) +} diff --git a/src/math/fminf16.rs b/src/math/fminf16.rs new file mode 100644 index 000000000..6d936be34 --- /dev/null +++ b/src/math/fminf16.rs @@ -0,0 +1,5 @@ +/// Return the lesser of two arguments or, if either argument is NaN, the other argument. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fminf16(x: f16, y: f16) -> f16 { + super::generic::fmin(x, y) +} diff --git a/src/math/generic/fmax.rs b/src/math/generic/fmax.rs new file mode 100644 index 000000000..97803052b --- /dev/null +++ b/src/math/generic/fmax.rs @@ -0,0 +1,14 @@ +use super::super::Float; + +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn fmax(x: F, y: F) -> F { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x.is_nan() || x < y { y } else { x }) * F::ONE +} diff --git a/src/math/generic/fmin.rs b/src/math/generic/fmin.rs new file mode 100644 index 000000000..697f72004 --- /dev/null +++ b/src/math/generic/fmin.rs @@ -0,0 +1,13 @@ +use super::super::Float; + +pub fn fmin(x: F, y: F) -> F { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if y.is_nan() || x < y { x } else { y }) * F::ONE +} diff --git a/src/math/generic/mod.rs b/src/math/generic/mod.rs index 1f557719f..819781a21 100644 --- a/src/math/generic/mod.rs +++ b/src/math/generic/mod.rs @@ -3,6 +3,8 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod fmax; +mod fmin; mod rint; mod round; mod scalbn; @@ -14,6 +16,8 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use fmax::fmax; +pub use fmin::fmin; pub use rint::rint; pub use round::round; pub use scalbn::scalbn; diff --git a/src/math/mod.rs b/src/math/mod.rs index 8db17a02d..cb83b2587 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -346,6 +346,8 @@ cfg_if! { mod fabsf16; mod fdimf16; mod floorf16; + mod fmaxf16; + mod fminf16; mod rintf16; mod roundf16; mod sqrtf16; @@ -356,6 +358,8 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; + pub use self::fmaxf16::fmaxf16; + pub use self::fminf16::fminf16; pub use self::rintf16::rintf16; pub use self::roundf16::roundf16; pub use self::sqrtf16::sqrtf16; @@ -370,6 +374,8 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; + mod fmaxf128; + mod fminf128; mod rintf128; mod roundf128; mod sqrtf128; @@ -380,6 +386,8 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; + pub use self::fmaxf128::fmaxf128; + pub use self::fminf128::fminf128; pub use self::rintf128::rintf128; pub use self::roundf128::roundf128; pub use self::sqrtf128::sqrtf128;