Skip to content

Commit 403732b

Browse files
committed
Add copysign
1 parent 305532d commit 403732b

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ libm = { version = "0.2.0", optional = true }
2323
default = ["std"]
2424
std = []
2525
i128 = []
26+
copysign = []
2627

2728
[build-dependencies]
2829
autocfg = "1"

build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ fn main() {
1111
autocfg::emit("has_i128");
1212
}
1313

14+
if env::var_os("CARGO_FEATURE_COPYSIGN").is_some() || ac.probe_expression("f32::copysign") {
15+
autocfg::emit("has_copysign");
16+
}
17+
1418
ac.emit_expression_cfg(
1519
"unsafe { 1f64.to_int_unchecked::<i32>() }",
1620
"has_to_int_unchecked",

src/float.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,35 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
18401840
/// assert!(abs_difference < 1e-10);
18411841
/// ```
18421842
fn integer_decode(self) -> (u64, i16, i8);
1843+
1844+
/// Returns a number composed of the magnitude of `self` and the sign of
1845+
/// `sign`.
1846+
///
1847+
/// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
1848+
/// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
1849+
/// `sign` is returned.
1850+
///
1851+
/// # Examples
1852+
///
1853+
/// ```
1854+
/// use num_traits::Float;
1855+
///
1856+
/// let f = 3.5_f32;
1857+
///
1858+
/// assert_eq!(f.copysign(0.42), 3.5_f32);
1859+
/// assert_eq!(f.copysign(-0.42), -3.5_f32);
1860+
/// assert_eq!((-f).copysign(0.42), 3.5_f32);
1861+
/// assert_eq!((-f).copysign(-0.42), -3.5_f32);
1862+
///
1863+
/// assert!(f32::nan().copysign(1.0).is_nan());
1864+
/// ```
1865+
fn copysign(self, sign: Self) -> Self {
1866+
if self.is_sign_negative() == sign.is_sign_negative() {
1867+
self
1868+
} else {
1869+
self.neg()
1870+
}
1871+
}
18431872
}
18441873

18451874
#[cfg(feature = "std")]
@@ -1917,6 +1946,12 @@ macro_rules! float_impl_std {
19171946
Self::acosh(self) -> Self;
19181947
Self::atanh(self) -> Self;
19191948
}
1949+
1950+
#[cfg(has_copysign)]
1951+
#[inline]
1952+
fn copysign(self, sign: Self) -> Self {
1953+
Self::copysign(self, sign)
1954+
}
19201955
}
19211956
};
19221957
}
@@ -2048,6 +2083,7 @@ impl Float for f32 {
20482083
libm::atanhf as atanh(self) -> Self;
20492084
libm::fmaxf as max(self, other: Self) -> Self;
20502085
libm::fminf as min(self, other: Self) -> Self;
2086+
libm::copysignf as copysign(self, other: Self) -> Self;
20512087
}
20522088
}
20532089

@@ -2095,6 +2131,8 @@ impl Float for f64 {
20952131
libm::atanh as atanh(self) -> Self;
20962132
libm::fmax as max(self, other: Self) -> Self;
20972133
libm::fmin as min(self, other: Self) -> Self;
2134+
libm::copysign as copysign(self, sign: Self) -> Self;
2135+
libm::copysignf as copysignf(self, sign: Self) -> Self;
20982136
}
20992137
}
21002138

@@ -2243,4 +2281,44 @@ mod tests {
22432281
check::<f32>(1e-6);
22442282
check::<f64>(1e-12);
22452283
}
2284+
2285+
#[test]
2286+
fn copysign() {
2287+
use float::Float;
2288+
test_copysign_generic(2.0_f32, -2.0_f32, f32::nan());
2289+
test_copysign_generic(2.0_f64, -2.0_f64, f64::nan());
2290+
test_copysignf(2.0_f32, -2.0_f32, f32::nan());
2291+
}
2292+
2293+
fn test_copysignf(p: f32, n: f32, nan: f32) {
2294+
use core::ops::Neg;
2295+
2296+
assert!(p.is_sign_positive());
2297+
assert!(n.is_sign_negative());
2298+
assert!(nan.is_nan());
2299+
2300+
assert_eq!(p, p.copysign(p));
2301+
assert_eq!(p.neg(), p.copysign(n));
2302+
2303+
assert_eq!(n, n.copysign(n));
2304+
assert_eq!(n.neg(), n.copysign(p));
2305+
2306+
assert!(nan.copysign(p).is_sign_positive());
2307+
assert!(nan.copysign(n).is_sign_negative());
2308+
}
2309+
2310+
fn test_copysign_generic<F: ::float::Float + core::fmt::Debug>(p: F, n: F, nan: F) {
2311+
assert!(p.is_sign_positive());
2312+
assert!(n.is_sign_negative());
2313+
assert!(nan.is_nan());
2314+
2315+
assert_eq!(p, p.copysign(p));
2316+
assert_eq!(p.neg(), p.copysign(n));
2317+
2318+
assert_eq!(n, n.copysign(n));
2319+
assert_eq!(n.neg(), n.copysign(p));
2320+
2321+
assert!(nan.copysign(p).is_sign_positive());
2322+
assert!(nan.copysign(n).is_sign_negative());
2323+
}
22462324
}

0 commit comments

Comments
 (0)