mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Add is_normal and classify methods to Float trait
This commit is contained in:
parent
a9ac2b95f4
commit
cc51186be0
@ -11,6 +11,7 @@
|
||||
//! Operations and constants for `f32`
|
||||
|
||||
use num::{Zero, One, strconv};
|
||||
use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
|
||||
use prelude::*;
|
||||
|
||||
pub use cmath::c_float_targ_consts::*;
|
||||
@ -568,12 +569,39 @@ impl Float for f32 {
|
||||
*self == Float::infinity() || *self == Float::neg_infinity()
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is not infinite or NaN
|
||||
/// Returns `true` if the number is neither infinite or NaN
|
||||
#[inline(always)]
|
||||
fn is_finite(&self) -> bool {
|
||||
!(self.is_NaN() || self.is_infinite())
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is neither zero, infinite, subnormal or NaN
|
||||
#[inline(always)]
|
||||
fn is_normal(&self) -> bool {
|
||||
match self.classify() {
|
||||
FPNormal => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the floating point category of the number. If only one property is going to
|
||||
/// be tested, it is generally faster to use the specific predicate instead.
|
||||
fn classify(&self) -> FPCategory {
|
||||
static EXP_MASK: u32 = 0x7f800000;
|
||||
static MAN_MASK: u32 = 0x007fffff;
|
||||
|
||||
match (
|
||||
unsafe { ::cast::transmute::<f32,u32>(*self) } & EXP_MASK,
|
||||
unsafe { ::cast::transmute::<f32,u32>(*self) } & MAN_MASK
|
||||
) {
|
||||
(EXP_MASK, 0) => FPInfinite,
|
||||
(EXP_MASK, _) => FPNaN,
|
||||
(exp, _) if exp != 0 => FPNormal,
|
||||
_ if self.is_zero() => FPZero,
|
||||
_ => FPSubnormal,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn mantissa_digits() -> uint { 24 }
|
||||
|
||||
@ -846,6 +874,7 @@ impl num::FromStrRadix for f32 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use f32::*;
|
||||
use num::*;
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
|
||||
@ -1041,4 +1070,28 @@ mod tests {
|
||||
assert_eq!(Primitive::bits::<f32>(), sys::size_of::<f32>() * 8);
|
||||
assert_eq!(Primitive::bytes::<f32>(), sys::size_of::<f32>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
assert!(!Float::NaN::<f32>().is_normal());
|
||||
assert!(!Float::infinity::<f32>().is_normal());
|
||||
assert!(!Float::neg_infinity::<f32>().is_normal());
|
||||
assert!(!Zero::zero::<f32>().is_normal());
|
||||
assert!(!Float::neg_zero::<f32>().is_normal());
|
||||
assert!(1f32.is_normal());
|
||||
assert!(1e-37f32.is_normal());
|
||||
assert!(!1e-38f32.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
assert_eq!(Float::NaN::<f32>().classify(), FPNaN);
|
||||
assert_eq!(Float::infinity::<f32>().classify(), FPInfinite);
|
||||
assert_eq!(Float::neg_infinity::<f32>().classify(), FPInfinite);
|
||||
assert_eq!(Zero::zero::<f32>().classify(), FPZero);
|
||||
assert_eq!(Float::neg_zero::<f32>().classify(), FPZero);
|
||||
assert_eq!(1f32.classify(), FPNormal);
|
||||
assert_eq!(1e-37f32.classify(), FPNormal);
|
||||
assert_eq!(1e-38f32.classify(), FPSubnormal);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
use libc::c_int;
|
||||
use num::{Zero, One, strconv};
|
||||
use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
|
||||
use prelude::*;
|
||||
|
||||
pub use cmath::c_double_targ_consts::*;
|
||||
@ -611,12 +612,39 @@ impl Float for f64 {
|
||||
*self == Float::infinity() || *self == Float::neg_infinity()
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is not infinite or NaN
|
||||
/// Returns `true` if the number is neither infinite or NaN
|
||||
#[inline(always)]
|
||||
fn is_finite(&self) -> bool {
|
||||
!(self.is_NaN() || self.is_infinite())
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is neither zero, infinite, subnormal or NaN
|
||||
#[inline(always)]
|
||||
fn is_normal(&self) -> bool {
|
||||
match self.classify() {
|
||||
FPNormal => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the floating point category of the number. If only one property is going to
|
||||
/// be tested, it is generally faster to use the specific predicate instead.
|
||||
fn classify(&self) -> FPCategory {
|
||||
static EXP_MASK: u64 = 0x7ff0000000000000;
|
||||
static MAN_MASK: u64 = 0x000fffffffffffff;
|
||||
|
||||
match (
|
||||
unsafe { ::cast::transmute::<f64,u64>(*self) } & EXP_MASK,
|
||||
unsafe { ::cast::transmute::<f64,u64>(*self) } & MAN_MASK
|
||||
) {
|
||||
(EXP_MASK, 0) => FPInfinite,
|
||||
(EXP_MASK, _) => FPNaN,
|
||||
(exp, _) if exp != 0 => FPNormal,
|
||||
_ if self.is_zero() => FPZero,
|
||||
_ => FPSubnormal,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn mantissa_digits() -> uint { 53 }
|
||||
|
||||
@ -889,6 +917,7 @@ impl num::FromStrRadix for f64 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use f64::*;
|
||||
use num::*;
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
|
||||
@ -1088,4 +1117,27 @@ mod tests {
|
||||
assert_eq!(Primitive::bits::<f64>(), sys::size_of::<f64>() * 8);
|
||||
assert_eq!(Primitive::bytes::<f64>(), sys::size_of::<f64>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
assert!(!Float::NaN::<f64>().is_normal());
|
||||
assert!(!Float::infinity::<f64>().is_normal());
|
||||
assert!(!Float::neg_infinity::<f64>().is_normal());
|
||||
assert!(!Zero::zero::<f64>().is_normal());
|
||||
assert!(!Float::neg_zero::<f64>().is_normal());
|
||||
assert!(1f64.is_normal());
|
||||
assert!(1e-307f64.is_normal());
|
||||
assert!(!1e-308f64.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
assert_eq!(Float::NaN::<f64>().classify(), FPNaN);
|
||||
assert_eq!(Float::infinity::<f64>().classify(), FPInfinite);
|
||||
assert_eq!(Float::neg_infinity::<f64>().classify(), FPInfinite);
|
||||
assert_eq!(Zero::zero::<f64>().classify(), FPZero);
|
||||
assert_eq!(Float::neg_zero::<f64>().classify(), FPZero);
|
||||
assert_eq!(1e-307f64.classify(), FPNormal);
|
||||
assert_eq!(1e-308f64.classify(), FPSubnormal);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
use libc::c_int;
|
||||
use num::{Zero, One, strconv};
|
||||
use num::FPCategory;
|
||||
use prelude::*;
|
||||
|
||||
pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt};
|
||||
@ -782,32 +783,37 @@ impl Primitive for float {
|
||||
|
||||
impl Float for float {
|
||||
#[inline(always)]
|
||||
fn NaN() -> float { 0.0 / 0.0 }
|
||||
fn NaN() -> float { Float::NaN::<f64>() as float }
|
||||
|
||||
#[inline(always)]
|
||||
fn infinity() -> float { 1.0 / 0.0 }
|
||||
fn infinity() -> float { Float::infinity::<f64>() as float }
|
||||
|
||||
#[inline(always)]
|
||||
fn neg_infinity() -> float { -1.0 / 0.0 }
|
||||
fn neg_infinity() -> float { Float::neg_infinity::<f64>() as float }
|
||||
|
||||
#[inline(always)]
|
||||
fn neg_zero() -> float { -0.0 }
|
||||
fn neg_zero() -> float { Float::neg_zero::<f64>() as float }
|
||||
|
||||
/// Returns `true` if the number is NaN
|
||||
#[inline(always)]
|
||||
fn is_NaN(&self) -> bool { *self != *self }
|
||||
fn is_NaN(&self) -> bool { (*self as f64).is_NaN() }
|
||||
|
||||
/// Returns `true` if the number is infinite
|
||||
#[inline(always)]
|
||||
fn is_infinite(&self) -> bool {
|
||||
*self == Float::infinity() || *self == Float::neg_infinity()
|
||||
}
|
||||
fn is_infinite(&self) -> bool { (*self as f64).is_infinite() }
|
||||
|
||||
/// Returns `true` if the number is not infinite or NaN
|
||||
/// Returns `true` if the number is neither infinite or NaN
|
||||
#[inline(always)]
|
||||
fn is_finite(&self) -> bool {
|
||||
!(self.is_NaN() || self.is_infinite())
|
||||
}
|
||||
fn is_finite(&self) -> bool { (*self as f64).is_finite() }
|
||||
|
||||
/// Returns `true` if the number is neither zero, infinite, subnormal or NaN
|
||||
#[inline(always)]
|
||||
fn is_normal(&self) -> bool { (*self as f64).is_normal() }
|
||||
|
||||
/// Returns the floating point category of the number. If only one property is going to
|
||||
/// be tested, it is generally faster to use the specific predicate instead.
|
||||
#[inline(always)]
|
||||
fn classify(&self) -> FPCategory { (*self as f64).classify() }
|
||||
|
||||
#[inline(always)]
|
||||
fn mantissa_digits() -> uint { Float::mantissa_digits::<f64>() }
|
||||
@ -844,9 +850,7 @@ impl Float for float {
|
||||
/// than if the operations were performed separately
|
||||
///
|
||||
#[inline(always)]
|
||||
fn ln_1p(&self) -> float {
|
||||
(*self as f64).ln_1p() as float
|
||||
}
|
||||
fn ln_1p(&self) -> float { (*self as f64).ln_1p() as float }
|
||||
|
||||
///
|
||||
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
|
||||
@ -867,6 +871,7 @@ impl Float for float {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use num::*;
|
||||
use super::*;
|
||||
use prelude::*;
|
||||
|
||||
@ -1063,6 +1068,30 @@ mod tests {
|
||||
assert_eq!(Primitive::bytes::<float>(), sys::size_of::<float>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_normal() {
|
||||
assert!(!Float::NaN::<float>().is_normal());
|
||||
assert!(!Float::infinity::<float>().is_normal());
|
||||
assert!(!Float::neg_infinity::<float>().is_normal());
|
||||
assert!(!Zero::zero::<float>().is_normal());
|
||||
assert!(!Float::neg_zero::<float>().is_normal());
|
||||
assert!(1f.is_normal());
|
||||
assert!(1e-307f.is_normal());
|
||||
assert!(!1e-308f.is_normal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_classify() {
|
||||
assert_eq!(Float::NaN::<float>().classify(), FPNaN);
|
||||
assert_eq!(Float::infinity::<float>().classify(), FPInfinite);
|
||||
assert_eq!(Float::neg_infinity::<float>().classify(), FPInfinite);
|
||||
assert_eq!(Zero::zero::<float>().classify(), FPZero);
|
||||
assert_eq!(Float::neg_zero::<float>().classify(), FPZero);
|
||||
assert_eq!(1f.classify(), FPNormal);
|
||||
assert_eq!(1e-307f.classify(), FPNormal);
|
||||
assert_eq!(1e-308f.classify(), FPSubnormal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_to_str_exact_do_decimal() {
|
||||
let s = to_str_exact(5.0, 4u);
|
||||
|
@ -237,6 +237,23 @@ pub trait Int: Integer
|
||||
+ Bitwise
|
||||
+ BitCount {}
|
||||
|
||||
///
|
||||
/// Used for representing the classification of floating point numbers
|
||||
///
|
||||
#[deriving(Eq)]
|
||||
pub enum FPCategory {
|
||||
/// "Not a Number", often obtained by dividing by zero
|
||||
FPNaN,
|
||||
/// Positive or negative infinity
|
||||
FPInfinite ,
|
||||
/// Positive or negative zero
|
||||
FPZero,
|
||||
/// De-normalized floating point representation (less precise than `FPNormal`)
|
||||
FPSubnormal,
|
||||
/// A regular floating point number
|
||||
FPNormal,
|
||||
}
|
||||
|
||||
///
|
||||
/// Primitive floating point numbers
|
||||
///
|
||||
@ -253,6 +270,8 @@ pub trait Float: Real
|
||||
fn is_NaN(&self) -> bool;
|
||||
fn is_infinite(&self) -> bool;
|
||||
fn is_finite(&self) -> bool;
|
||||
fn is_normal(&self) -> bool;
|
||||
fn classify(&self) -> FPCategory;
|
||||
|
||||
fn mantissa_digits() -> uint;
|
||||
fn digits() -> uint;
|
||||
|
Loading…
Reference in New Issue
Block a user