Make `Float` and `Real` depend on the `std` feature
We don't have implementations for many of the methods in `no_std`. It's hostile to external implementors if some trait methods are conditional on a feature, as that feature could be added by anyone in a dependency tree. Instead, let's just live without these traits for now.
This commit is contained in:
parent
a843027b56
commit
e6bb97b3ac
|
@ -1,9 +1,9 @@
|
|||
use core::f64;
|
||||
use core::mem::size_of;
|
||||
use core::num::Wrapping;
|
||||
|
||||
use identities::Zero;
|
||||
use bounds::Bounded;
|
||||
use float::Float;
|
||||
|
||||
/// A generic trait for converting a value to a number.
|
||||
pub trait ToPrimitive {
|
||||
|
@ -228,7 +228,9 @@ macro_rules! impl_to_primitive_float_to_float {
|
|||
// NaN and +-inf are cast as they are.
|
||||
let n = $slf as f64;
|
||||
let max_value: $DstT = ::core::$DstT::MAX;
|
||||
if !Float::is_finite(n) || (-max_value as f64 <= n && n <= max_value as f64) {
|
||||
if n != n || n == f64::INFINITY || n == f64::NEG_INFINITY
|
||||
|| (-max_value as f64 <= n && n <= max_value as f64)
|
||||
{
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
|
|
20
src/float.rs
20
src/float.rs
|
@ -1,15 +1,24 @@
|
|||
#[cfg(feature = "std")]
|
||||
use std::mem;
|
||||
#[cfg(feature = "std")]
|
||||
use std::ops::Neg;
|
||||
#[cfg(feature = "std")]
|
||||
use std::num::FpCategory;
|
||||
|
||||
// Used for default implementation of `epsilon`
|
||||
#[cfg(feature = "std")]
|
||||
use std::f32;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use {Num, NumCast};
|
||||
|
||||
// FIXME: these doctests aren't actually helpful, because they're using and
|
||||
// testing the inherent methods directly, not going through `Float`.
|
||||
|
||||
/// Generic trait for floating point numbers
|
||||
///
|
||||
/// This trait is only available with the `std` feature.
|
||||
#[cfg(feature = "std")]
|
||||
pub trait Float
|
||||
: Num
|
||||
+ Copy
|
||||
|
@ -923,6 +932,7 @@ pub trait Float
|
|||
fn integer_decode(self) -> (u64, i16, i8);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
macro_rules! float_impl {
|
||||
($T:ident $decode:ident) => (
|
||||
impl Float for $T {
|
||||
|
@ -1219,6 +1229,7 @@ macro_rules! float_impl {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
|
||||
let bits: u32 = unsafe { mem::transmute(f) };
|
||||
let sign: i8 = if bits >> 31 == 0 {
|
||||
|
@ -1237,6 +1248,7 @@ fn integer_decode_f32(f: f32) -> (u64, i16, i8) {
|
|||
(mantissa as u64, exponent, sign)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
|
||||
let bits: u64 = unsafe { mem::transmute(f) };
|
||||
let sign: i8 = if bits >> 63 == 0 {
|
||||
|
@ -1255,7 +1267,9 @@ fn integer_decode_f64(f: f64) -> (u64, i16, i8) {
|
|||
(mantissa, exponent, sign)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
float_impl!(f32 integer_decode_f32);
|
||||
#[cfg(feature = "std")]
|
||||
float_impl!(f64 integer_decode_f64);
|
||||
|
||||
macro_rules! float_const_impl {
|
||||
|
@ -1272,7 +1286,7 @@ macro_rules! float_const_impl {
|
|||
$(
|
||||
#[inline]
|
||||
fn $constant() -> Self {
|
||||
::std::$T::consts::$constant
|
||||
::core::$T::consts::$constant
|
||||
}
|
||||
)+
|
||||
}
|
||||
|
@ -1314,13 +1328,13 @@ float_const_impl! {
|
|||
SQRT_2,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
mod tests {
|
||||
use Float;
|
||||
|
||||
#[test]
|
||||
fn convert_deg_rad() {
|
||||
use std::f64::consts;
|
||||
use core::f64::consts;
|
||||
|
||||
const DEG_RAD_PAIRS: [(f64, f64); 7] = [
|
||||
(0.0, 0.),
|
||||
|
|
35
src/lib.rs
35
src/lib.rs
|
@ -24,7 +24,9 @@ use core::num::Wrapping;
|
|||
use core::fmt;
|
||||
|
||||
pub use bounds::Bounded;
|
||||
pub use float::{Float, FloatConst};
|
||||
#[cfg(feature = "std")]
|
||||
pub use float::Float;
|
||||
pub use float::FloatConst;
|
||||
// pub use real::Real; // NOTE: Don't do this, it breaks `use num_traits::*;`.
|
||||
pub use identities::{Zero, One, zero, one};
|
||||
pub use ops::checked::*;
|
||||
|
@ -40,6 +42,7 @@ pub mod sign;
|
|||
pub mod ops;
|
||||
pub mod bounds;
|
||||
pub mod float;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod real;
|
||||
pub mod cast;
|
||||
pub mod int;
|
||||
|
@ -187,7 +190,7 @@ impl fmt::Display for ParseFloatError {
|
|||
// with this implementation ourselves until we want to make a breaking change.
|
||||
// (would have to drop it from `Num` though)
|
||||
macro_rules! float_trait_impl {
|
||||
($name:ident for $($t:ty)*) => ($(
|
||||
($name:ident for $($t:ident)*) => ($(
|
||||
impl $name for $t {
|
||||
type FromStrRadixErr = ParseFloatError;
|
||||
|
||||
|
@ -199,9 +202,9 @@ macro_rules! float_trait_impl {
|
|||
|
||||
// Special values
|
||||
match src {
|
||||
"inf" => return Ok(Float::infinity()),
|
||||
"-inf" => return Ok(Float::neg_infinity()),
|
||||
"NaN" => return Ok(Float::nan()),
|
||||
"inf" => return Ok(core::$t::INFINITY),
|
||||
"-inf" => return Ok(core::$t::NEG_INFINITY),
|
||||
"NaN" => return Ok(core::$t::NAN),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
|
@ -242,15 +245,15 @@ macro_rules! float_trait_impl {
|
|||
// if we've not seen any non-zero digits.
|
||||
if prev_sig != 0.0 {
|
||||
if is_positive && sig <= prev_sig
|
||||
{ return Ok(Float::infinity()); }
|
||||
{ return Ok(core::$t::INFINITY); }
|
||||
if !is_positive && sig >= prev_sig
|
||||
{ return Ok(Float::neg_infinity()); }
|
||||
{ return Ok(core::$t::NEG_INFINITY); }
|
||||
|
||||
// Detect overflow by reversing the shift-and-add process
|
||||
if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
|
||||
{ return Ok(Float::infinity()); }
|
||||
{ return Ok(core::$t::INFINITY); }
|
||||
if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
|
||||
{ return Ok(Float::neg_infinity()); }
|
||||
{ return Ok(core::$t::NEG_INFINITY); }
|
||||
}
|
||||
prev_sig = sig;
|
||||
},
|
||||
|
@ -286,9 +289,9 @@ macro_rules! float_trait_impl {
|
|||
};
|
||||
// Detect overflow by comparing to last value
|
||||
if is_positive && sig < prev_sig
|
||||
{ return Ok(Float::infinity()); }
|
||||
{ return Ok(core::$t::INFINITY); }
|
||||
if !is_positive && sig > prev_sig
|
||||
{ return Ok(Float::neg_infinity()); }
|
||||
{ return Ok(core::$t::NEG_INFINITY); }
|
||||
prev_sig = sig;
|
||||
},
|
||||
None => match c {
|
||||
|
@ -322,9 +325,15 @@ macro_rules! float_trait_impl {
|
|||
None => return Err(PFE { kind: Invalid }),
|
||||
};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn pow(base: $t, exp: usize) -> $t {
|
||||
Float::powi(base, exp as i32)
|
||||
}
|
||||
// otherwise uses the generic `pow` from the root
|
||||
|
||||
match (is_positive, exp) {
|
||||
(true, Ok(exp)) => Float::powi(base, exp as i32),
|
||||
(false, Ok(exp)) => 1.0 / Float::powi(base, exp as i32),
|
||||
(true, Ok(exp)) => pow(base, exp),
|
||||
(false, Ok(exp)) => 1.0 / pow(base, exp),
|
||||
(_, Err(_)) => return Err(PFE { kind: Invalid }),
|
||||
}
|
||||
},
|
||||
|
|
|
@ -10,6 +10,8 @@ use {Num, NumCast, Float};
|
|||
///
|
||||
/// See [this Wikipedia article](https://en.wikipedia.org/wiki/Real_data_type)
|
||||
/// for a list of data types that could meaningfully implement this trait.
|
||||
///
|
||||
/// This trait is only available with the `std` feature.
|
||||
pub trait Real
|
||||
: Num
|
||||
+ Copy
|
||||
|
|
35
src/sign.rs
35
src/sign.rs
|
@ -2,7 +2,7 @@ use core::ops::Neg;
|
|||
use core::{f32, f64};
|
||||
use core::num::Wrapping;
|
||||
|
||||
use {Num, Float};
|
||||
use Num;
|
||||
|
||||
/// Useful functions for signed numbers (i.e. numbers that can be negative).
|
||||
pub trait Signed: Sized + Num + Neg<Output = Self> {
|
||||
|
@ -103,10 +103,24 @@ macro_rules! signed_float_impl {
|
|||
impl Signed for $t {
|
||||
/// Computes the absolute value. Returns `NAN` if the number is `NAN`.
|
||||
#[inline]
|
||||
#[cfg(feature = "std")]
|
||||
fn abs(&self) -> $t {
|
||||
(*self).abs()
|
||||
}
|
||||
|
||||
/// Computes the absolute value. Returns `NAN` if the number is `NAN`.
|
||||
#[inline]
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn abs(&self) -> $t {
|
||||
if self.is_positive() {
|
||||
*self
|
||||
} else if self.is_negative() {
|
||||
-*self
|
||||
} else {
|
||||
$nan
|
||||
}
|
||||
}
|
||||
|
||||
/// The positive difference of two numbers. Returns `0.0` if the number is
|
||||
/// less than or equal to `other`, otherwise the difference between`self`
|
||||
/// and `other` is returned.
|
||||
|
@ -121,10 +135,29 @@ macro_rules! signed_float_impl {
|
|||
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
|
||||
/// - `NAN` if the number is NaN
|
||||
#[inline]
|
||||
#[cfg(feature = "std")]
|
||||
fn signum(&self) -> $t {
|
||||
use Float;
|
||||
Float::signum(*self)
|
||||
}
|
||||
|
||||
/// # Returns
|
||||
///
|
||||
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
|
||||
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
|
||||
/// - `NAN` if the number is NaN
|
||||
#[inline]
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn signum(&self) -> $t {
|
||||
if self.is_positive() {
|
||||
1.0
|
||||
} else if self.is_negative() {
|
||||
-1.0
|
||||
} else {
|
||||
$nan
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
|
||||
#[inline]
|
||||
fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == $inf }
|
||||
|
|
Loading…
Reference in New Issue