Browse Source

Revive Float+Real in no_std with libm

Yoan Lecoq 6 years ago
parent
commit
fec6c3610c
4 changed files with 79 additions and 13 deletions
  1. 1 0
      Cargo.toml
  2. 71 9
      src/float.rs
  3. 5 2
      src/lib.rs
  4. 2 2
      src/real.rs

+ 1 - 0
Cargo.toml

@@ -17,6 +17,7 @@ exclude = ["/ci/*", "/.travis.yml", "/bors.toml"]
 features = ["std"]
 
 [dependencies]
+libm = { version = "~0.1.2", optional = true }
 
 [features]
 default = ["std"]

+ 71 - 9
src/float.rs

@@ -7,6 +7,9 @@ use core::f64;
 
 use {Num, NumCast, ToPrimitive};
 
+#[cfg(feature = "libm")]
+use libm::{F32Ext, F64Ext};
+
 /// Generic trait for floating point numbers that works with `no_std`.
 ///
 /// This trait implements a subset of the `Float` trait.
@@ -897,8 +900,8 @@ impl FloatCore for f64 {
 
 /// Generic trait for floating point numbers
 ///
-/// This trait is only available with the `std` feature.
-#[cfg(feature = "std")]
+/// This trait is only available with the `std` feature, or with the `libm` feature otherwise.
+#[cfg(any(feature = "std", feature = "libm"))]
 pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
     /// Returns the `NaN` value.
     ///
@@ -1805,9 +1808,9 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
     fn integer_decode(self) -> (u64, i16, i8);
 }
 
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", feature = "libm"))]
 macro_rules! float_impl {
-    ($T:ident $decode:ident) => {
+    ($T:ident $decode:ident $LibmImpl:ident) => {
         impl Float for $T {
             constant! {
                 nan() -> $T::NAN;
@@ -1820,17 +1823,26 @@ macro_rules! float_impl {
                 max_value() -> $T::MAX;
             }
 
+            #[cfg(feature = "std")]
             #[inline]
             #[allow(deprecated)]
             fn abs_sub(self, other: Self) -> Self {
                 <$T>::abs_sub(self, other)
             }
 
+            #[cfg(all(not(feature = "std"), feature = "libm"))]
+            #[inline]
+            #[allow(deprecated)]
+            fn abs_sub(self, other: Self) -> Self {
+                <$T as $LibmImpl>::fdim(self, other)
+            }
+
             #[inline]
             fn integer_decode(self) -> (u64, i16, i8) {
                 $decode(self)
             }
 
+            #[cfg(feature = "std")]
             forward! {
                 Self::is_nan(self) -> bool;
                 Self::is_infinite(self) -> bool;
@@ -1880,6 +1892,56 @@ macro_rules! float_impl {
                 Self::acosh(self) -> Self;
                 Self::atanh(self) -> Self;
             }
+            #[cfg(all(not(feature = "std"), feature = "libm"))]
+            forward! {
+                FloatCore::is_nan(self) -> bool;
+                FloatCore::is_infinite(self) -> bool;
+                FloatCore::is_finite(self) -> bool;
+                FloatCore::is_normal(self) -> bool;
+                FloatCore::classify(self) -> FpCategory;
+                $LibmImpl::floor(self) -> Self;
+                $LibmImpl::ceil(self) -> Self;
+                $LibmImpl::round(self) -> Self;
+                $LibmImpl::trunc(self) -> Self;
+                $LibmImpl::fract(self) -> Self;
+                $LibmImpl::abs(self) -> Self;
+                FloatCore::signum(self) -> Self;
+                FloatCore::is_sign_positive(self) -> bool;
+                FloatCore::is_sign_negative(self) -> bool;
+                $LibmImpl::mul_add(self, a: Self, b: Self) -> Self;
+                FloatCore::recip(self) -> Self;
+                FloatCore::powi(self, n: i32) -> Self;
+                $LibmImpl::powf(self, n: Self) -> Self;
+                $LibmImpl::sqrt(self) -> Self;
+                $LibmImpl::exp(self) -> Self;
+                $LibmImpl::exp2(self) -> Self;
+                $LibmImpl::ln(self) -> Self;
+                $LibmImpl::log(self, base: Self) -> Self;
+                $LibmImpl::log2(self) -> Self;
+                $LibmImpl::log10(self) -> Self;
+                FloatCore::to_degrees(self) -> Self;
+                FloatCore::to_radians(self) -> Self;
+                FloatCore::max(self, other: Self) -> Self;
+                FloatCore::min(self, other: Self) -> Self;
+                $LibmImpl::cbrt(self) -> Self;
+                $LibmImpl::hypot(self, other: Self) -> Self;
+                $LibmImpl::sin(self) -> Self;
+                $LibmImpl::cos(self) -> Self;
+                $LibmImpl::tan(self) -> Self;
+                $LibmImpl::asin(self) -> Self;
+                $LibmImpl::acos(self) -> Self;
+                $LibmImpl::atan(self) -> Self;
+                $LibmImpl::atan2(self, other: Self) -> Self;
+                $LibmImpl::sin_cos(self) -> (Self, Self);
+                $LibmImpl::exp_m1(self) -> Self;
+                $LibmImpl::ln_1p(self) -> Self;
+                $LibmImpl::sinh(self) -> Self;
+                $LibmImpl::cosh(self) -> Self;
+                $LibmImpl::tanh(self) -> Self;
+                $LibmImpl::asinh(self) -> Self;
+                $LibmImpl::acosh(self) -> Self;
+                $LibmImpl::atanh(self) -> Self;
+            }
         }
     };
 }
@@ -1916,10 +1978,10 @@ 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);
+#[cfg(any(feature = "std", feature = "libm"))]
+float_impl!(f32 integer_decode_f32 F32Ext);
+#[cfg(any(feature = "std", feature = "libm"))]
+float_impl!(f64 integer_decode_f64 F64Ext);
 
 macro_rules! float_const_impl {
     ($(#[$doc:meta] $constant:ident,)+) => (
@@ -2002,7 +2064,7 @@ mod tests {
         }
     }
 
-    #[cfg(feature = "std")]
+    #[cfg(any(feature = "std", feature = "libm"))]
     #[test]
     fn convert_deg_rad_std() {
         for &(deg, rad) in &DEG_RAD_PAIRS {

+ 5 - 2
src/lib.rs

@@ -20,13 +20,16 @@
 #[cfg(feature = "std")]
 extern crate std;
 
+#[cfg(feature = "libm")]
+extern crate libm;
+
 use core::fmt;
 use core::num::Wrapping;
 use core::ops::{Add, Div, Mul, Rem, Sub};
 use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
 
 pub use bounds::Bounded;
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", feature = "libm"))]
 pub use float::Float;
 pub use float::FloatConst;
 // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
@@ -53,7 +56,7 @@ pub mod identities;
 pub mod int;
 pub mod ops;
 pub mod pow;
-#[cfg(feature = "std")]
+#[cfg(any(feature = "std", feature = "libm"))]
 pub mod real;
 pub mod sign;
 

+ 2 - 2
src/real.rs

@@ -1,4 +1,4 @@
-use std::ops::Neg;
+use core::ops::Neg;
 
 use {Float, Num, NumCast};
 
@@ -11,7 +11,7 @@ use {Float, Num, NumCast};
 /// 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.
+/// This trait is only available with the `std` feature, or with the `libm` feature otherwise.
 pub trait Real: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
     /// Returns the smallest finite value that this type can represent.
     ///