From 64db6c32936c1cd00c3074b847e10c7e6f8b20b3 Mon Sep 17 00:00:00 2001 From: Erin Power Date: Wed, 17 Mar 2021 08:17:38 +0100 Subject: [PATCH 1/7] Add copysign --- Cargo.toml | 1 + build.rs | 4 +++ src/float.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 8d88bf44..813d36d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ libm = { version = "0.2.0", optional = true } default = ["std"] std = [] i128 = [] +copysign = [] [build-dependencies] autocfg = "1" diff --git a/build.rs b/build.rs index 887021d9..66931b4d 100644 --- a/build.rs +++ b/build.rs @@ -11,6 +11,10 @@ fn main() { autocfg::emit("has_i128"); } + if env::var_os("CARGO_FEATURE_COPYSIGN").is_some() || ac.probe_expression("f32::copysign") { + autocfg::emit("has_copysign"); + } + ac.emit_expression_cfg( "unsafe { 1f64.to_int_unchecked::() }", "has_to_int_unchecked", diff --git a/src/float.rs b/src/float.rs index 38e3833e..5cda43e5 100644 --- a/src/float.rs +++ b/src/float.rs @@ -1862,6 +1862,35 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg { /// assert!(abs_difference < 1e-10); /// ``` fn integer_decode(self) -> (u64, i16, i8); + + /// Returns a number composed of the magnitude of `self` and the sign of + /// `sign`. + /// + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise + /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of + /// `sign` is returned. + /// + /// # Examples + /// + /// ``` + /// use num_traits::Float; + /// + /// let f = 3.5_f32; + /// + /// assert_eq!(f.copysign(0.42), 3.5_f32); + /// assert_eq!(f.copysign(-0.42), -3.5_f32); + /// assert_eq!((-f).copysign(0.42), 3.5_f32); + /// assert_eq!((-f).copysign(-0.42), -3.5_f32); + /// + /// assert!(f32::nan().copysign(1.0).is_nan()); + /// ``` + fn copysign(self, sign: Self) -> Self { + if self.is_sign_negative() == sign.is_sign_negative() { + self + } else { + self.neg() + } + } } #[cfg(feature = "std")] @@ -1939,6 +1968,12 @@ macro_rules! float_impl_std { Self::acosh(self) -> Self; Self::atanh(self) -> Self; } + + #[cfg(has_copysign)] + #[inline] + fn copysign(self, sign: Self) -> Self { + Self::copysign(self, sign) + } } }; } @@ -2070,6 +2105,7 @@ impl Float for f32 { libm::atanhf as atanh(self) -> Self; libm::fmaxf as max(self, other: Self) -> Self; libm::fminf as min(self, other: Self) -> Self; + libm::copysignf as copysign(self, other: Self) -> Self; } } @@ -2117,6 +2153,8 @@ impl Float for f64 { libm::atanh as atanh(self) -> Self; libm::fmax as max(self, other: Self) -> Self; libm::fmin as min(self, other: Self) -> Self; + libm::copysign as copysign(self, sign: Self) -> Self; + libm::copysignf as copysignf(self, sign: Self) -> Self; } } @@ -2265,4 +2303,44 @@ mod tests { check::(1e-6); check::(1e-12); } + + #[test] + fn copysign() { + use float::Float; + test_copysign_generic(2.0_f32, -2.0_f32, f32::nan()); + test_copysign_generic(2.0_f64, -2.0_f64, f64::nan()); + test_copysignf(2.0_f32, -2.0_f32, f32::nan()); + } + + fn test_copysignf(p: f32, n: f32, nan: f32) { + use core::ops::Neg; + + assert!(p.is_sign_positive()); + assert!(n.is_sign_negative()); + assert!(nan.is_nan()); + + assert_eq!(p, p.copysign(p)); + assert_eq!(p.neg(), p.copysign(n)); + + assert_eq!(n, n.copysign(n)); + assert_eq!(n.neg(), n.copysign(p)); + + assert!(nan.copysign(p).is_sign_positive()); + assert!(nan.copysign(n).is_sign_negative()); + } + + fn test_copysign_generic(p: F, n: F, nan: F) { + assert!(p.is_sign_positive()); + assert!(n.is_sign_negative()); + assert!(nan.is_nan()); + + assert_eq!(p, p.copysign(p)); + assert_eq!(p.neg(), p.copysign(n)); + + assert_eq!(n, n.copysign(n)); + assert_eq!(n.neg(), n.copysign(p)); + + assert!(nan.copysign(p).is_sign_positive()); + assert!(nan.copysign(n).is_sign_negative()); + } } From 7ca2456e9c1b3f89a6bb749fc54d8a153ff51704 Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Thu, 28 Oct 2021 09:14:01 +0200 Subject: [PATCH 2/7] Update float.rs --- src/float.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/float.rs b/src/float.rs index 5cda43e5..87fcc4d7 100644 --- a/src/float.rs +++ b/src/float.rs @@ -2154,7 +2154,6 @@ impl Float for f64 { libm::fmax as max(self, other: Self) -> Self; libm::fmin as min(self, other: Self) -> Self; libm::copysign as copysign(self, sign: Self) -> Self; - libm::copysignf as copysignf(self, sign: Self) -> Self; } } From cabfb0b90497ba5d908d14a908dd269f03cc5f4d Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Thu, 28 Oct 2021 09:15:39 +0200 Subject: [PATCH 3/7] Update float.rs --- src/float.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/float.rs b/src/float.rs index 87fcc4d7..5c8da695 100644 --- a/src/float.rs +++ b/src/float.rs @@ -2304,6 +2304,7 @@ mod tests { } #[test] + #[cfg(any(feature = "std", feature = "libm"))] fn copysign() { use float::Float; test_copysign_generic(2.0_f32, -2.0_f32, f32::nan()); @@ -2311,7 +2312,9 @@ mod tests { test_copysignf(2.0_f32, -2.0_f32, f32::nan()); } + #[cfg(any(feature = "std", feature = "libm"))] fn test_copysignf(p: f32, n: f32, nan: f32) { + use float::Float; use core::ops::Neg; assert!(p.is_sign_positive()); From 70b5c579ab6a001435208d8d3811407c8f07fa94 Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Thu, 28 Oct 2021 09:16:48 +0200 Subject: [PATCH 4/7] Update float.rs --- src/float.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/float.rs b/src/float.rs index 5c8da695..632e3e59 100644 --- a/src/float.rs +++ b/src/float.rs @@ -2304,7 +2304,7 @@ mod tests { } #[test] - #[cfg(any(feature = "std", feature = "libm"))] + #[cfg(any(feature = "std", feature = "libm"))] fn copysign() { use float::Float; test_copysign_generic(2.0_f32, -2.0_f32, f32::nan()); @@ -2331,6 +2331,7 @@ mod tests { assert!(nan.copysign(n).is_sign_negative()); } + #[cfg(any(feature = "std", feature = "libm"))] fn test_copysign_generic(p: F, n: F, nan: F) { assert!(p.is_sign_positive()); assert!(n.is_sign_negative()); From 30f8d3ab4bfb590f742f592309109e00b207b23d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 29 Apr 2022 18:20:38 -0700 Subject: [PATCH 5/7] Make sure test_copysignf uses Float --- src/float.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/float.rs b/src/float.rs index 632e3e59..87a92a95 100644 --- a/src/float.rs +++ b/src/float.rs @@ -2314,21 +2314,21 @@ mod tests { #[cfg(any(feature = "std", feature = "libm"))] fn test_copysignf(p: f32, n: f32, nan: f32) { - use float::Float; use core::ops::Neg; + use float::Float; assert!(p.is_sign_positive()); assert!(n.is_sign_negative()); assert!(nan.is_nan()); - assert_eq!(p, p.copysign(p)); - assert_eq!(p.neg(), p.copysign(n)); + assert_eq!(p, Float::copysign(p, p)); + assert_eq!(p.neg(), Float::copysign(p, n)); - assert_eq!(n, n.copysign(n)); - assert_eq!(n.neg(), n.copysign(p)); + assert_eq!(n, Float::copysign(n, n)); + assert_eq!(n.neg(), Float::copysign(n, p)); - assert!(nan.copysign(p).is_sign_positive()); - assert!(nan.copysign(n).is_sign_negative()); + assert!(Float::copysign(nan, p).is_sign_positive()); + assert!(Float::copysign(nan, n).is_sign_negative()); } #[cfg(any(feature = "std", feature = "libm"))] From 30077120f96ff00de46cab3c6ce693eb892c18bd Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 29 Apr 2022 18:20:55 -0700 Subject: [PATCH 6/7] Don't use an explicit copysign feature --- Cargo.toml | 1 - build.rs | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 813d36d2..8d88bf44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ libm = { version = "0.2.0", optional = true } default = ["std"] std = [] i128 = [] -copysign = [] [build-dependencies] autocfg = "1" diff --git a/build.rs b/build.rs index 66931b4d..c7bf364f 100644 --- a/build.rs +++ b/build.rs @@ -11,10 +11,6 @@ fn main() { autocfg::emit("has_i128"); } - if env::var_os("CARGO_FEATURE_COPYSIGN").is_some() || ac.probe_expression("f32::copysign") { - autocfg::emit("has_copysign"); - } - ac.emit_expression_cfg( "unsafe { 1f64.to_int_unchecked::() }", "has_to_int_unchecked", @@ -25,5 +21,9 @@ fn main() { ac.emit_expression_cfg("{ let mut x = 1; x += &2; }", "has_int_assignop_ref"); ac.emit_expression_cfg("1u32.div_euclid(1u32)", "has_div_euclid"); + if env::var_os("CARGO_FEATURE_STD").is_some() { + ac.emit_expression_cfg("1f64.copysign(-1f64)", "has_copysign"); + } + autocfg::rerun_path("build.rs"); } From e4e52de40fdf4fa5f2ef260a482cf51c915581c5 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 29 Apr 2022 18:35:25 -0700 Subject: [PATCH 7/7] Fix copysign tests for 1.8.0 --- src/float.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/float.rs b/src/float.rs index 87a92a95..47bd6543 100644 --- a/src/float.rs +++ b/src/float.rs @@ -2327,12 +2327,13 @@ mod tests { assert_eq!(n, Float::copysign(n, n)); assert_eq!(n.neg(), Float::copysign(n, p)); - assert!(Float::copysign(nan, p).is_sign_positive()); - assert!(Float::copysign(nan, n).is_sign_negative()); + // FIXME: is_sign... only works on NaN starting in Rust 1.20 + // assert!(Float::copysign(nan, p).is_sign_positive()); + // assert!(Float::copysign(nan, n).is_sign_negative()); } #[cfg(any(feature = "std", feature = "libm"))] - fn test_copysign_generic(p: F, n: F, nan: F) { + fn test_copysign_generic(p: F, n: F, nan: F) { assert!(p.is_sign_positive()); assert!(n.is_sign_negative()); assert!(nan.is_nan()); @@ -2343,7 +2344,8 @@ mod tests { assert_eq!(n, n.copysign(n)); assert_eq!(n.neg(), n.copysign(p)); - assert!(nan.copysign(p).is_sign_positive()); - assert!(nan.copysign(n).is_sign_negative()); + // FIXME: is_sign... only works on NaN starting in Rust 1.20 + // assert!(nan.copysign(p).is_sign_positive()); + // assert!(nan.copysign(n).is_sign_negative()); } }