From baa89afffecce87acd384c9c94ec4ae933f68765 Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Sat, 20 Oct 2018 17:47:32 +0200 Subject: [PATCH] Embed nan-preserving-float crate. --- Cargo.toml | 1 - src/lib.rs | 3 +- src/nan_preserving_float.rs | 212 ++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 src/nan_preserving_float.rs diff --git a/Cargo.toml b/Cargo.toml index ba2f1c2..30d38ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ parity-wasm = { version = "0.31", default-features = false } byteorder = { version = "1.0", default-features = false } hashmap_core = { version = "0.1.9", optional = true } memory_units = "0.3.0" -nan-preserving-float = "0.1.0" libm = { version = "0.1.2", optional = true } [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index cea7c3b..c0d6162 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,8 +123,6 @@ extern crate byteorder; extern crate hashmap_core; extern crate memory_units as memory_units_crate; -pub extern crate nan_preserving_float; - #[allow(unused_imports)] use alloc::prelude::*; use core::fmt; @@ -392,6 +390,7 @@ mod global; mod func; mod types; mod isa; +pub mod nan_preserving_float; #[cfg(test)] mod tests; diff --git a/src/nan_preserving_float.rs b/src/nan_preserving_float.rs new file mode 100644 index 0000000..6579662 --- /dev/null +++ b/src/nan_preserving_float.rs @@ -0,0 +1,212 @@ +#![allow(missing_docs)] + +#[cfg(not(feature = "std"))] +use libm::{F32Ext, F64Ext}; + +use core::ops::{Add, Div, Mul, Neg, Sub, Rem}; +use core::cmp::{Ordering, PartialEq, PartialOrd}; + +macro_rules! impl_binop { + ($for:ident, $is:ident, $op:ident, $func_name:ident) => { + impl> $op for $for { + type Output = Self; + + fn $func_name(self, other: T) -> Self { + $for( + $op::$func_name( + $is::from_bits(self.0), + $is::from_bits(other.into().0) + ).to_bits() + ) + } + } + } +} + +macro_rules! float { + ($for:ident, $rep:ident, $is:ident) => { + float!($for, $rep, $is, 1 << (::core::mem::size_of::<$is>() * 8 - 1)); + }; + ($for:ident, $rep:ident, $is:ident, $sign_bit:expr) => { + #[derive(Copy, Clone)] + pub struct $for($rep); + + impl_binop!($for, $is, Add, add); + impl_binop!($for, $is, Sub, sub); + impl_binop!($for, $is, Mul, mul); + impl_binop!($for, $is, Div, div); + impl_binop!($for, $is, Rem, rem); + + impl $for { + pub fn from_bits(other: $rep) -> Self { + $for(other) + } + + pub fn to_bits(self) -> $rep { + self.0 + } + + pub fn from_float(fl: $is) -> Self { + fl.into() + } + + pub fn to_float(self) -> $is { + self.into() + } + + pub fn is_nan(self) -> bool { + self.to_float().is_nan() + } + + pub fn abs(self) -> Self { + $for(self.0 & !$sign_bit) + } + + pub fn fract(self) -> Self { + self.to_float().fract().into() + } + + pub fn min(self, other: Self) -> Self { + Self::from(self.to_float().min(other.to_float())) + } + + pub fn max(self, other: Self) -> Self { + Self::from(self.to_float().max(other.to_float())) + } + } + + impl From<$is> for $for { + fn from(other: $is) -> $for { + $for(other.to_bits()) + } + } + + impl From<$for> for $is { + fn from(other: $for) -> $is { + <$is>::from_bits(other.0) + } + } + + impl Neg for $for { + type Output = Self; + + fn neg(self) -> Self { + $for(self.0 ^ $sign_bit) + } + } + + impl + Copy> PartialEq for $for { + fn eq(&self, other: &T) -> bool { + $is::from(*self) == $is::from((*other).into()) + } + } + + impl + Copy> PartialOrd for $for { + fn partial_cmp(&self, other: &T) -> Option { + $is::from(*self).partial_cmp(&$is::from((*other).into())) + } + } + + impl ::core::fmt::Debug for $for { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + $is::from(*self).fmt(f) + } + } + } +} + +float!(F32, u32, f32); +float!(F64, u64, f64); + +impl From for F32 { + fn from(other: u32) -> Self { + Self::from_bits(other) + } +} + +impl From for u32 { + fn from(other: F32) -> Self { + other.to_bits() + } +} + +impl From for F64 { + fn from(other: u64) -> Self { + Self::from_bits(other) + } +} + +impl From for u64 { + fn from(other: F64) -> Self { + other.to_bits() + } +} + +#[cfg(test)] +mod tests { + extern crate rand; + + use self::rand::Rng; + + use super::{F32, F64}; + + use core::ops::{Add, Div, Mul, Neg, Sub}; + use core::fmt::Debug; + use core::iter; + + fn test_ops(iter: I) + where + T: Add + + Div + + Mul + + Sub + + Neg + + Copy + + Debug + + PartialEq, + F: Into + + Add + + Div + + Mul + + Sub + + Neg + + Copy + + Debug, + I: IntoIterator, + { + for (a, b) in iter { + assert_eq!((a + b).into(), a.into() + b.into()); + assert_eq!((a - b).into(), a.into() - b.into()); + assert_eq!((a * b).into(), a.into() * b.into()); + assert_eq!((a / b).into(), a.into() / b.into()); + assert_eq!((-a).into(), -a.into()); + assert_eq!((-b).into(), -b.into()); + } + } + + #[test] + fn test_ops_f32() { + let mut rng = rand::thread_rng(); + let iter = iter::repeat(()).map(|_| rng.gen()); + + test_ops::(iter.take(1000)); + } + + #[test] + fn test_ops_f64() { + let mut rng = rand::thread_rng(); + let iter = iter::repeat(()).map(|_| rng.gen()); + + test_ops::(iter.take(1000)); + } + + #[test] + fn test_neg_nan_f32() { + assert_eq!((-F32(0xff80_3210)).0, 0x7f80_3210); + } + + #[test] + fn test_neg_nan_f64() { + assert_eq!((-F64(0xff80_3210_0000_0000)).0, 0x7f80_3210_0000_0000); + } +}