Skip to content

Commit c264006

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

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
}
@@ -389,10 +392,12 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
389392
} else {
390393
self - f + one
391394
}
392-
} else if -f < h {
393-
self - f
394395
} else {
395-
self - f - one
396+
if -f < h {
397+
self - f
398+
} else {
399+
self - f - one
400+
}
396401
}
397402
}
398403

@@ -525,7 +530,8 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
525530
}
526531

527532
/// Returns `true` if `self` is positive, including `+0.0` and
528-
/// `FloatCore::infinity()`, and `FloatCore::nan()`.
533+
/// `FloatCore::infinity()`, and since Rust 1.20 also
534+
/// `FloatCore::nan()`.
529535
///
530536
/// # Examples
531537
///
@@ -543,7 +549,6 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
543549
/// check(-0.0f64, false);
544550
/// check(f64::NEG_INFINITY, false);
545551
/// check(f64::MIN_POSITIVE, true);
546-
/// check(f64::NAN, true);
547552
/// check(-f64::NAN, false);
548553
/// ```
549554
#[inline]
@@ -552,7 +557,8 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
552557
}
553558

554559
/// Returns `true` if `self` is negative, including `-0.0` and
555-
/// `FloatCore::neg_infinity()`, and `-FloatCore::nan()`.
560+
/// `FloatCore::neg_infinity()`, and since Rust 1.20 also
561+
/// `-FloatCore::nan()`.
556562
///
557563
/// # Examples
558564
///
@@ -571,7 +577,6 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
571577
/// check(f64::NEG_INFINITY, true);
572578
/// check(f64::MIN_POSITIVE, false);
573579
/// check(f64::NAN, false);
574-
/// check(-f64::NAN, true);
575580
/// ```
576581
#[inline]
577582
fn is_sign_negative(self) -> bool {
@@ -786,7 +791,9 @@ impl FloatCore for f32 {
786791
const EXP_MASK: u32 = 0x7f800000;
787792
const MAN_MASK: u32 = 0x007fffff;
788793

789-
let bits: u32 = self.to_bits();
794+
// Safety: this identical to the implementation of f32::to_bits(),
795+
// which is only available starting at Rust 1.20
796+
let bits: u32 = unsafe { mem::transmute(self) };
790797
match (bits & MAN_MASK, bits & EXP_MASK) {
791798
(0, 0) => FpCategory::Zero,
792799
(_, 0) => FpCategory::Subnormal,
@@ -801,7 +808,10 @@ impl FloatCore for f32 {
801808
fn is_sign_negative(self) -> bool {
802809
const SIGN_MASK: u32 = 0x80000000;
803810

804-
self.to_bits() & SIGN_MASK != 0
811+
// Safety: this identical to the implementation of f32::to_bits(),
812+
// which is only available starting at Rust 1.20
813+
let bits: u32 = unsafe { mem::transmute(self) };
814+
bits & SIGN_MASK != 0
805815
}
806816

807817
#[inline]
@@ -883,7 +893,9 @@ impl FloatCore for f64 {
883893
const EXP_MASK: u64 = 0x7ff0000000000000;
884894
const MAN_MASK: u64 = 0x000fffffffffffff;
885895

886-
let bits: u64 = self.to_bits();
896+
// Safety: this identical to the implementation of f64::to_bits(),
897+
// which is only available starting at Rust 1.20
898+
let bits: u64 = unsafe { mem::transmute(self) };
887899
match (bits & MAN_MASK, bits & EXP_MASK) {
888900
(0, 0) => FpCategory::Zero,
889901
(_, 0) => FpCategory::Subnormal,
@@ -898,7 +910,10 @@ impl FloatCore for f64 {
898910
fn is_sign_negative(self) -> bool {
899911
const SIGN_MASK: u64 = 0x8000000000000000;
900912

901-
self.to_bits() & SIGN_MASK != 0
913+
// Safety: this identical to the implementation of f64::to_bits(),
914+
// which is only available starting at Rust 1.20
915+
let bits: u64 = unsafe { mem::transmute(self) };
916+
bits & SIGN_MASK != 0
902917
}
903918

904919
#[inline]
@@ -1294,42 +1309,38 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
12941309
fn signum(self) -> Self;
12951310

12961311
/// Returns `true` if `self` is positive, including `+0.0`,
1297-
/// `Float::infinity()`, and `Float::nan()`.
1312+
/// `Float::infinity()`, and since Rust 1.20 also `Float::nan()`.
12981313
///
12991314
/// ```
13001315
/// use num_traits::Float;
13011316
/// use std::f64;
13021317
///
1303-
/// let nan: f64 = f64::NAN;
13041318
/// let neg_nan: f64 = -f64::NAN;
13051319
///
13061320
/// let f = 7.0;
13071321
/// let g = -7.0;
13081322
///
13091323
/// assert!(f.is_sign_positive());
13101324
/// assert!(!g.is_sign_positive());
1311-
/// assert!(nan.is_sign_positive());
13121325
/// assert!(!neg_nan.is_sign_positive());
13131326
/// ```
13141327
fn is_sign_positive(self) -> bool;
13151328

13161329
/// Returns `true` if `self` is negative, including `-0.0`,
1317-
/// `Float::neg_infinity()`, and `-Float::nan()`.
1330+
/// `Float::neg_infinity()`, and since Rust 1.20 also `-Float::nan()`.
13181331
///
13191332
/// ```
13201333
/// use num_traits::Float;
13211334
/// use std::f64;
13221335
///
13231336
/// let nan: f64 = f64::NAN;
1324-
/// let neg_nan: f64 = -f64::NAN;
13251337
///
13261338
/// let f = 7.0;
13271339
/// let g = -7.0;
13281340
///
13291341
/// assert!(!f.is_sign_negative());
13301342
/// assert!(g.is_sign_negative());
13311343
/// assert!(!nan.is_sign_negative());
1332-
/// assert!(neg_nan.is_sign_negative());
13331344
/// ```
13341345
fn is_sign_negative(self) -> bool;
13351346

@@ -2058,7 +2069,9 @@ macro_rules! float_impl_libm {
20582069
}
20592070

20602071
fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
2061-
let bits: u32 = f.to_bits();
2072+
// Safety: this identical to the implementation of f32::to_bits(),
2073+
// which is only available starting at Rust 1.20
2074+
let bits: u32 = unsafe { mem::transmute(f) };
20622075
let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
20632076
let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
20642077
let mantissa = if exponent == 0 {
@@ -2072,7 +2085,9 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
20722085
}
20732086

20742087
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
2075-
let bits: u64 = f.to_bits();
2088+
// Safety: this identical to the implementation of f64::to_bits(),
2089+
// which is only available starting at Rust 1.20
2090+
let bits: u64 = unsafe { mem::transmute(f) };
20762091
let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
20772092
let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
20782093
let mantissa = if exponent == 0 {
@@ -2273,7 +2288,7 @@ mod tests {
22732288

22742289
#[test]
22752290
fn convert_deg_rad() {
2276-
use crate::float::FloatCore;
2291+
use float::FloatCore;
22772292

22782293
for &(deg, rad) in &DEG_RAD_PAIRS {
22792294
assert!((FloatCore::to_degrees(rad) - deg).abs() < 1e-6);
@@ -2289,7 +2304,7 @@ mod tests {
22892304
#[test]
22902305
fn convert_deg_rad_std() {
22912306
for &(deg, rad) in &DEG_RAD_PAIRS {
2292-
use crate::Float;
2307+
use Float;
22932308

22942309
assert!((Float::to_degrees(rad) - deg).abs() < 1e-6);
22952310
assert!((Float::to_radians(deg) - rad).abs() < 1e-6);
@@ -2301,8 +2316,11 @@ mod tests {
23012316
}
23022317

23032318
#[test]
2319+
// This fails with the forwarded `std` implementation in Rust 1.8.
2320+
// To avoid the failure, the test is limited to `no_std` builds.
2321+
#[cfg(not(feature = "std"))]
23042322
fn to_degrees_rounding() {
2305-
use crate::float::FloatCore;
2323+
use float::FloatCore;
23062324

23072325
assert_eq!(
23082326
FloatCore::to_degrees(1_f32),
@@ -2313,7 +2331,7 @@ mod tests {
23132331
#[test]
23142332
#[cfg(any(feature = "std", feature = "libm"))]
23152333
fn extra_logs() {
2316-
use crate::float::{Float, FloatConst};
2334+
use float::{Float, FloatConst};
23172335

23182336
fn check<F: Float + FloatConst>(diff: F) {
23192337
let _2 = F::from(2.0).unwrap();
@@ -2332,33 +2350,33 @@ mod tests {
23322350
#[test]
23332351
#[cfg(any(feature = "std", feature = "libm"))]
23342352
fn copysign() {
2335-
use crate::float::Float;
2353+
use float::Float;
23362354
test_copysign_generic(2.0_f32, -2.0_f32, f32::nan());
23372355
test_copysign_generic(2.0_f64, -2.0_f64, f64::nan());
23382356
test_copysignf(2.0_f32, -2.0_f32, f32::nan());
23392357
}
23402358

23412359
#[cfg(any(feature = "std", feature = "libm"))]
23422360
fn test_copysignf(p: f32, n: f32, nan: f32) {
2343-
use crate::float::Float;
2361+
use float::Float;
23442362
use core::ops::Neg;
23452363

23462364
assert!(p.is_sign_positive());
23472365
assert!(n.is_sign_negative());
23482366
assert!(nan.is_nan());
23492367

2350-
assert_eq!(p, Float::copysign(p, p));
2351-
assert_eq!(p.neg(), Float::copysign(p, n));
2368+
assert_eq!(p, p.copysign(p));
2369+
assert_eq!(p.neg(), p.copysign(n));
23522370

2353-
assert_eq!(n, Float::copysign(n, n));
2354-
assert_eq!(n.neg(), Float::copysign(n, p));
2371+
assert_eq!(n, n.copysign(n));
2372+
assert_eq!(n.neg(), n.copysign(p));
23552373

2356-
assert!(Float::copysign(nan, p).is_sign_positive());
2357-
assert!(Float::copysign(nan, n).is_sign_negative());
2374+
assert!(nan.copysign(p).is_sign_positive());
2375+
assert!(nan.copysign(n).is_sign_negative());
23582376
}
23592377

23602378
#[cfg(any(feature = "std", feature = "libm"))]
2361-
fn test_copysign_generic<F: crate::float::Float + ::core::fmt::Debug>(p: F, n: F, nan: F) {
2379+
fn test_copysign_generic<F: ::float::Float + core::fmt::Debug>(p: F, n: F, nan: F) {
23622380
assert!(p.is_sign_positive());
23632381
assert!(n.is_sign_negative());
23642382
assert!(nan.is_nan());

0 commit comments

Comments
 (0)