Skip to content

Commit

Permalink
Add copysign
Browse files Browse the repository at this point in the history
  • Loading branch information
XAMPPRocky committed Apr 22, 2021
1 parent 305532d commit e6e9769
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -23,6 +23,7 @@ libm = { version = "0.2.0", optional = true }
default = ["std"]
std = []
i128 = []
copysign = []

[build-dependencies]
autocfg = "1"
4 changes: 4 additions & 0 deletions build.rs
Expand Up @@ -11,6 +11,10 @@ fn main() {
autocfg::emit("has_i128");
}

if env::var_os("CARGO_FEATURE_COPYSIGN").is_some() || ac.probe_path("f32::copysign") {
autocfg::emit("has_copysign");
}

ac.emit_expression_cfg(
"unsafe { 1f64.to_int_unchecked::<i32>() }",
"has_to_int_unchecked",
Expand Down
63 changes: 63 additions & 0 deletions src/float.rs
Expand Up @@ -1840,6 +1840,35 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
/// 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")]
Expand Down Expand Up @@ -1917,6 +1946,11 @@ macro_rules! float_impl_std {
Self::acosh(self) -> Self;
Self::atanh(self) -> Self;
}

#[cfg(has_copysign)]
forward! {
Self::copysign(self, sign: Self) -> Self;
}
}
};
}
Expand Down Expand Up @@ -2096,6 +2130,11 @@ impl Float for f64 {
libm::fmax as max(self, other: Self) -> Self;
libm::fmin as min(self, other: Self) -> Self;
}

#[cfg(has_copysign)]
forward! {
libm::copysign as copysign(self, sign: Self) -> Self;
}
}

macro_rules! float_const_impl {
Expand Down Expand Up @@ -2243,4 +2282,28 @@ mod tests {
check::<f32>(1e-6);
check::<f64>(1e-12);
}

#[cfg(all(any(feature = "std", feature = "libm"), has_copysign))]
#[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());
}

#[cfg(all(any(feature = "std", feature = "libm"), has_copysign))]
fn test_copysign_generic<F: ::float::Float + core::fmt::Debug>(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());
}
}

0 comments on commit e6e9769

Please sign in to comment.