Skip to content

Commit 60fd4ea

Browse files
XAMPPRockyctrlcctrlv
authored andcommitted
Add copysign (upstream PR rust-num#207)
Signed-off-by: Fredrick Brennan <[email protected]>
1 parent b5906ee commit 60fd4ea

File tree

3 files changed

+65
-39
lines changed

3 files changed

+65
-39
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ std = []
2727

2828
# vestigial features, now always in effect
2929
i128 = []
30+
copysign = []
3031

3132
[build-dependencies]
3233
autocfg = "1"

build.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
1+
extern crate autocfg;
2+
13
use std::env;
24

35
fn main() {
46
let ac = autocfg::new();
57

8+
// If the "i128" feature is explicity requested, don't bother probing for it.
9+
// It will still cause a build error if that was set improperly.
10+
if env::var_os("CARGO_FEATURE_I128").is_some() || ac.probe_type("i128") {
11+
autocfg::emit("has_i128");
12+
}
13+
14+
if env::var_os("CARGO_FEATURE_COPYSIGN").is_some() || ac.probe_expression("f32::copysign") {
15+
autocfg::emit("has_copysign");
16+
}
17+
618
ac.emit_expression_cfg(
719
"unsafe { 1f64.to_int_unchecked::<i32>() }",
820
"has_to_int_unchecked",
921
);
1022

1123
ac.emit_expression_cfg("1u32.reverse_bits()", "has_reverse_bits");
1224
ac.emit_expression_cfg("1u32.trailing_ones()", "has_leading_trailing_ones");
13-
ac.emit_expression_cfg("1u32.div_euclid(1u32)", "has_div_euclid");
14-
15-
if env::var_os("CARGO_FEATURE_STD").is_some() {
16-
ac.emit_expression_cfg("1f64.copysign(-1f64)", "has_copysign");
17-
}
1825

1926
autocfg::rerun_path("build.rs");
2027
}

src/float.rs

+52-34
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
use core::mem;
12
use core::num::FpCategory;
23
use core::ops::{Add, Div, Neg};
34

45
use core::f32;
56
use core::f64;
67

7-
use crate::{Num, NumCast, ToPrimitive};
8+
use {Num, NumCast, ToPrimitive};
9+
10+
#[cfg(all(not(feature = "std"), feature = "libm"))]
11+
use libm;
812

913
/// Generic trait for floating point numbers that works with `no_std`.
1014
///
@@ -166,7 +170,6 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
166170
/// check(0.0f64, false);
167171
/// ```
168172
#[inline]
169-
#[allow(clippy::eq_op)]
170173
fn is_nan(self) -> bool {
171174
self != self
172175
}
@@ -367,10 +370,12 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
367370
} else {
368371
self - f + one
369372
}
370-
} else if -f < h {
371-
self - f
372373
} else {
373-
self - f - one
374+
if -f < h {
375+
self - f
376+
} else {
377+
self - f - one
378+
}
374379
}
375380
}
376381

@@ -503,7 +508,8 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
503508
}
504509

505510
/// Returns `true` if `self` is positive, including `+0.0` and
506-
/// `FloatCore::infinity()`, and `FloatCore::nan()`.
511+
/// `FloatCore::infinity()`, and since Rust 1.20 also
512+
/// `FloatCore::nan()`.
507513
///
508514
/// # Examples
509515
///
@@ -521,7 +527,6 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
521527
/// check(-0.0f64, false);
522528
/// check(f64::NEG_INFINITY, false);
523529
/// check(f64::MIN_POSITIVE, true);
524-
/// check(f64::NAN, true);
525530
/// check(-f64::NAN, false);
526531
/// ```
527532
#[inline]
@@ -530,7 +535,8 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
530535
}
531536

532537
/// Returns `true` if `self` is negative, including `-0.0` and
533-
/// `FloatCore::neg_infinity()`, and `-FloatCore::nan()`.
538+
/// `FloatCore::neg_infinity()`, and since Rust 1.20 also
539+
/// `-FloatCore::nan()`.
534540
///
535541
/// # Examples
536542
///
@@ -549,7 +555,6 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
549555
/// check(f64::NEG_INFINITY, true);
550556
/// check(f64::MIN_POSITIVE, false);
551557
/// check(f64::NAN, false);
552-
/// check(-f64::NAN, true);
553558
/// ```
554559
#[inline]
555560
fn is_sign_negative(self) -> bool {
@@ -764,7 +769,9 @@ impl FloatCore for f32 {
764769
const EXP_MASK: u32 = 0x7f800000;
765770
const MAN_MASK: u32 = 0x007fffff;
766771

767-
let bits: u32 = self.to_bits();
772+
// Safety: this identical to the implementation of f32::to_bits(),
773+
// which is only available starting at Rust 1.20
774+
let bits: u32 = unsafe { mem::transmute(self) };
768775
match (bits & MAN_MASK, bits & EXP_MASK) {
769776
(0, 0) => FpCategory::Zero,
770777
(_, 0) => FpCategory::Subnormal,
@@ -779,7 +786,10 @@ impl FloatCore for f32 {
779786
fn is_sign_negative(self) -> bool {
780787
const SIGN_MASK: u32 = 0x80000000;
781788

782-
self.to_bits() & SIGN_MASK != 0
789+
// Safety: this identical to the implementation of f32::to_bits(),
790+
// which is only available starting at Rust 1.20
791+
let bits: u32 = unsafe { mem::transmute(self) };
792+
bits & SIGN_MASK != 0
783793
}
784794

785795
#[inline]
@@ -861,7 +871,9 @@ impl FloatCore for f64 {
861871
const EXP_MASK: u64 = 0x7ff0000000000000;
862872
const MAN_MASK: u64 = 0x000fffffffffffff;
863873

864-
let bits: u64 = self.to_bits();
874+
// Safety: this identical to the implementation of f64::to_bits(),
875+
// which is only available starting at Rust 1.20
876+
let bits: u64 = unsafe { mem::transmute(self) };
865877
match (bits & MAN_MASK, bits & EXP_MASK) {
866878
(0, 0) => FpCategory::Zero,
867879
(_, 0) => FpCategory::Subnormal,
@@ -876,7 +888,10 @@ impl FloatCore for f64 {
876888
fn is_sign_negative(self) -> bool {
877889
const SIGN_MASK: u64 = 0x8000000000000000;
878890

879-
self.to_bits() & SIGN_MASK != 0
891+
// Safety: this identical to the implementation of f64::to_bits(),
892+
// which is only available starting at Rust 1.20
893+
let bits: u64 = unsafe { mem::transmute(self) };
894+
bits & SIGN_MASK != 0
880895
}
881896

882897
#[inline]
@@ -1251,42 +1266,38 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
12511266
fn signum(self) -> Self;
12521267

12531268
/// Returns `true` if `self` is positive, including `+0.0`,
1254-
/// `Float::infinity()`, and `Float::nan()`.
1269+
/// `Float::infinity()`, and since Rust 1.20 also `Float::nan()`.
12551270
///
12561271
/// ```
12571272
/// use num_traits::Float;
12581273
/// use std::f64;
12591274
///
1260-
/// let nan: f64 = f64::NAN;
12611275
/// let neg_nan: f64 = -f64::NAN;
12621276
///
12631277
/// let f = 7.0;
12641278
/// let g = -7.0;
12651279
///
12661280
/// assert!(f.is_sign_positive());
12671281
/// assert!(!g.is_sign_positive());
1268-
/// assert!(nan.is_sign_positive());
12691282
/// assert!(!neg_nan.is_sign_positive());
12701283
/// ```
12711284
fn is_sign_positive(self) -> bool;
12721285

12731286
/// Returns `true` if `self` is negative, including `-0.0`,
1274-
/// `Float::neg_infinity()`, and `-Float::nan()`.
1287+
/// `Float::neg_infinity()`, and since Rust 1.20 also `-Float::nan()`.
12751288
///
12761289
/// ```
12771290
/// use num_traits::Float;
12781291
/// use std::f64;
12791292
///
12801293
/// let nan: f64 = f64::NAN;
1281-
/// let neg_nan: f64 = -f64::NAN;
12821294
///
12831295
/// let f = 7.0;
12841296
/// let g = -7.0;
12851297
///
12861298
/// assert!(!f.is_sign_negative());
12871299
/// assert!(g.is_sign_negative());
12881300
/// assert!(!nan.is_sign_negative());
1289-
/// assert!(neg_nan.is_sign_negative());
12901301
/// ```
12911302
fn is_sign_negative(self) -> bool;
12921303

@@ -2014,7 +2025,9 @@ macro_rules! float_impl_libm {
20142025
}
20152026

20162027
fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
2017-
let bits: u32 = f.to_bits();
2028+
// Safety: this identical to the implementation of f32::to_bits(),
2029+
// which is only available starting at Rust 1.20
2030+
let bits: u32 = unsafe { mem::transmute(f) };
20182031
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
20192032
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
20202033
let mantissa = if exponent == 0 {
@@ -2028,7 +2041,9 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
20282041
}
20292042

20302043
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
2031-
let bits: u64 = f.to_bits();
2044+
// Safety: this identical to the implementation of f64::to_bits(),
2045+
// which is only available starting at Rust 1.20
2046+
let bits: u64 = unsafe { mem::transmute(f) };
20322047
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
20332048
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
20342049
let mantissa = if exponent == 0 {
@@ -2229,7 +2244,7 @@ mod tests {
22292244

22302245
#[test]
22312246
fn convert_deg_rad() {
2232-
use crate::float::FloatCore;
2247+
use float::FloatCore;
22332248

22342249
for &(deg, rad) in &DEG_RAD_PAIRS {
22352250
assert!((FloatCore::to_degrees(rad) - deg).abs() < 1e-6);
@@ -2245,7 +2260,7 @@ mod tests {
22452260
#[test]
22462261
fn convert_deg_rad_std() {
22472262
for &(deg, rad) in &DEG_RAD_PAIRS {
2248-
use crate::Float;
2263+
use Float;
22492264

22502265
assert!((Float::to_degrees(rad) - deg).abs() < 1e-6);
22512266
assert!((Float::to_radians(deg) - rad).abs() < 1e-6);
@@ -2257,8 +2272,11 @@ mod tests {
22572272
}
22582273

22592274
#[test]
2275+
// This fails with the forwarded `std` implementation in Rust 1.8.
2276+
// To avoid the failure, the test is limited to `no_std` builds.
2277+
#[cfg(not(feature = "std"))]
22602278
fn to_degrees_rounding() {
2261-
use crate::float::FloatCore;
2279+
use float::FloatCore;
22622280

22632281
assert_eq!(
22642282
FloatCore::to_degrees(1_f32),
@@ -2269,7 +2287,7 @@ mod tests {
22692287
#[test]
22702288
#[cfg(any(feature = "std", feature = "libm"))]
22712289
fn extra_logs() {
2272-
use crate::float::{Float, FloatConst};
2290+
use float::{Float, FloatConst};
22732291

22742292
fn check<F: Float + FloatConst>(diff: F) {
22752293
let _2 = F::from(2.0).unwrap();
@@ -2288,33 +2306,33 @@ mod tests {
22882306
#[test]
22892307
#[cfg(any(feature = "std", feature = "libm"))]
22902308
fn copysign() {
2291-
use crate::float::Float;
2309+
use float::Float;
22922310
test_copysign_generic(2.0_f32, -2.0_f32, f32::nan());
22932311
test_copysign_generic(2.0_f64, -2.0_f64, f64::nan());
22942312
test_copysignf(2.0_f32, -2.0_f32, f32::nan());
22952313
}
22962314

22972315
#[cfg(any(feature = "std", feature = "libm"))]
22982316
fn test_copysignf(p: f32, n: f32, nan: f32) {
2299-
use crate::float::Float;
2317+
use float::Float;
23002318
use core::ops::Neg;
23012319

23022320
assert!(p.is_sign_positive());
23032321
assert!(n.is_sign_negative());
23042322
assert!(nan.is_nan());
23052323

2306-
assert_eq!(p, Float::copysign(p, p));
2307-
assert_eq!(p.neg(), Float::copysign(p, n));
2324+
assert_eq!(p, p.copysign(p));
2325+
assert_eq!(p.neg(), p.copysign(n));
23082326

2309-
assert_eq!(n, Float::copysign(n, n));
2310-
assert_eq!(n.neg(), Float::copysign(n, p));
2327+
assert_eq!(n, n.copysign(n));
2328+
assert_eq!(n.neg(), n.copysign(p));
23112329

2312-
assert!(Float::copysign(nan, p).is_sign_positive());
2313-
assert!(Float::copysign(nan, n).is_sign_negative());
2330+
assert!(nan.copysign(p).is_sign_positive());
2331+
assert!(nan.copysign(n).is_sign_negative());
23142332
}
23152333

23162334
#[cfg(any(feature = "std", feature = "libm"))]
2317-
fn test_copysign_generic<F: crate::float::Float + ::core::fmt::Debug>(p: F, n: F, nan: F) {
2335+
fn test_copysign_generic<F: ::float::Float + core::fmt::Debug>(p: F, n: F, nan: F) {
23182336
assert!(p.is_sign_positive());
23192337
assert!(n.is_sign_negative());
23202338
assert!(nan.is_nan());

0 commit comments

Comments
 (0)