Skip to content

Commit c263032

Browse files
bors[bot]ctrlcctrlvcuviper
authored
Merge #279
279: Add FloatCore and Float::is_subnormal r=cuviper a=cuviper This is a rebase of #265, adding a default impl and an autocfg check. Closes #264. Co-authored-by: Fredrick Brennan <copypaste@kittens.ph> Co-authored-by: Josh Stone <cuviper@gmail.com>
2 parents 85edb5e + 58b46b1 commit c263032

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
1.38.0, # has_div_euclid
2020
1.44.0, # has_to_int_unchecked
2121
1.46.0, # has_leading_trailing_ones
22+
1.53.0, # has_is_subnormal
2223
stable,
2324
beta,
2425
nightly,

bors.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ status = [
55
"Test (1.38.0)",
66
"Test (1.44.0)",
77
"Test (1.46.0)",
8+
"Test (1.53.0)",
89
"Test (stable)",
910
"Test (beta)",
1011
"Test (nightly)",

build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fn main() {
1515
if env::var_os("CARGO_FEATURE_STD").is_some() {
1616
ac.emit_expression_cfg("1f64.copysign(-1f64)", "has_copysign");
1717
}
18+
ac.emit_expression_cfg("1f64.is_subnormal()", "has_is_subnormal");
1819

1920
autocfg::rerun_path("build.rs");
2021
}

ci/rustup.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
set -ex
66

77
ci=$(dirname $0)
8-
for version in 1.31.0 1.35.0 1.37.0 1.38.0 1.44.0 1.46.0 stable beta nightly; do
8+
for version in 1.31.0 1.35.0 1.37.0 1.38.0 1.44.0 1.46.0 1.53.0 stable beta nightly; do
99
rustup run "$version" "$ci/test_full.sh"
1010
done

src/float.rs

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,32 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
241241
self.classify() == FpCategory::Normal
242242
}
243243

244+
/// Returns `true` if the number is [subnormal].
245+
///
246+
/// ```
247+
/// use num_traits::float::FloatCore;
248+
/// use std::f64;
249+
///
250+
/// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64
251+
/// let max = f64::MAX;
252+
/// let lower_than_min = 1.0e-308_f64;
253+
/// let zero = 0.0_f64;
254+
///
255+
/// assert!(!min.is_subnormal());
256+
/// assert!(!max.is_subnormal());
257+
///
258+
/// assert!(!zero.is_subnormal());
259+
/// assert!(!f64::NAN.is_subnormal());
260+
/// assert!(!f64::INFINITY.is_subnormal());
261+
/// // Values between `0` and `min` are Subnormal.
262+
/// assert!(lower_than_min.is_subnormal());
263+
/// ```
264+
/// [subnormal]: https://en.wikipedia.org/wiki/Subnormal_number
265+
#[inline]
266+
fn is_subnormal(self) -> bool {
267+
self.classify() == FpCategory::Subnormal
268+
}
269+
244270
/// Returns the floating point category of the number. If only one property
245271
/// is going to be tested, it is generally faster to use the specific
246272
/// predicate instead.
@@ -918,6 +944,11 @@ impl FloatCore for f64 {
918944
Self::to_radians(self) -> Self;
919945
}
920946

947+
#[cfg(has_is_subnormal)]
948+
forward! {
949+
Self::is_subnormal(self) -> bool;
950+
}
951+
921952
#[cfg(all(not(feature = "std"), feature = "libm"))]
922953
forward! {
923954
libm::floor as floor(self) -> Self;
@@ -1123,9 +1154,35 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
11231154
/// // Values between `0` and `min` are Subnormal.
11241155
/// assert!(!lower_than_min.is_normal());
11251156
/// ```
1126-
/// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number
1157+
/// [subnormal]: http://en.wikipedia.org/wiki/Subnormal_number
11271158
fn is_normal(self) -> bool;
11281159

1160+
/// Returns `true` if the number is [subnormal].
1161+
///
1162+
/// ```
1163+
/// use num_traits::Float;
1164+
/// use std::f64;
1165+
///
1166+
/// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308_f64
1167+
/// let max = f64::MAX;
1168+
/// let lower_than_min = 1.0e-308_f64;
1169+
/// let zero = 0.0_f64;
1170+
///
1171+
/// assert!(!min.is_subnormal());
1172+
/// assert!(!max.is_subnormal());
1173+
///
1174+
/// assert!(!zero.is_subnormal());
1175+
/// assert!(!f64::NAN.is_subnormal());
1176+
/// assert!(!f64::INFINITY.is_subnormal());
1177+
/// // Values between `0` and `min` are Subnormal.
1178+
/// assert!(lower_than_min.is_subnormal());
1179+
/// ```
1180+
/// [subnormal]: https://en.wikipedia.org/wiki/Subnormal_number
1181+
#[inline]
1182+
fn is_subnormal(self) -> bool {
1183+
self.classify() == FpCategory::Subnormal
1184+
}
1185+
11291186
/// Returns the floating point category of the number. If only one property
11301187
/// is going to be tested, it is generally faster to use the specific
11311188
/// predicate instead.
@@ -1959,9 +2016,13 @@ macro_rules! float_impl_std {
19592016
}
19602017

19612018
#[cfg(has_copysign)]
1962-
#[inline]
1963-
fn copysign(self, sign: Self) -> Self {
1964-
Self::copysign(self, sign)
2019+
forward! {
2020+
Self::copysign(self, sign: Self) -> Self;
2021+
}
2022+
2023+
#[cfg(has_is_subnormal)]
2024+
forward! {
2025+
Self::is_subnormal(self) -> bool;
19652026
}
19662027
}
19672028
};
@@ -2318,6 +2379,7 @@ mod tests {
23182379
assert!(p.is_sign_positive());
23192380
assert!(n.is_sign_negative());
23202381
assert!(nan.is_nan());
2382+
assert!(!nan.is_subnormal());
23212383

23222384
assert_eq!(p, p.copysign(p));
23232385
assert_eq!(p.neg(), p.copysign(n));
@@ -2328,4 +2390,19 @@ mod tests {
23282390
assert!(nan.copysign(p).is_sign_positive());
23292391
assert!(nan.copysign(n).is_sign_negative());
23302392
}
2393+
2394+
#[cfg(any(feature = "std", feature = "libm"))]
2395+
fn test_subnormal<F: crate::float::Float + ::core::fmt::Debug>() {
2396+
let min_positive = F::min_positive_value();
2397+
let lower_than_min = min_positive / F::from(2.0f32).unwrap();
2398+
assert!(!min_positive.is_subnormal());
2399+
assert!(lower_than_min.is_subnormal());
2400+
}
2401+
2402+
#[test]
2403+
#[cfg(any(feature = "std", feature = "libm"))]
2404+
fn subnormal() {
2405+
test_subnormal::<f64>();
2406+
test_subnormal::<f32>();
2407+
}
23312408
}

0 commit comments

Comments
 (0)