use libm for float math in no_std
This commit is contained in:
parent
2a6103c29f
commit
0a0f8707c4
|
@ -16,7 +16,7 @@ default = ["std"]
|
||||||
std = ["parity-wasm/std", "byteorder/std"]
|
std = ["parity-wasm/std", "byteorder/std"]
|
||||||
# Enable for no_std support
|
# Enable for no_std support
|
||||||
# hashmap_core only works on no_std
|
# hashmap_core only works on no_std
|
||||||
core = ["hashmap_core"]
|
core = ["hashmap_core", "libm"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-wasm = { version = "0.31", default-features = false }
|
parity-wasm = { version = "0.31", default-features = false }
|
||||||
|
@ -24,6 +24,7 @@ byteorder = { version = "1.0", default-features = false }
|
||||||
hashmap_core = { version = "0.1.9", optional = true }
|
hashmap_core = { version = "0.1.9", optional = true }
|
||||||
memory_units = "0.3.0"
|
memory_units = "0.3.0"
|
||||||
nan-preserving-float = "0.1.0"
|
nan-preserving-float = "0.1.0"
|
||||||
|
libm = { version = "0.1.2", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.1"
|
assert_matches = "1.1"
|
||||||
|
|
|
@ -131,6 +131,9 @@ use core::fmt;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::error;
|
use std::error;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
extern crate libm;
|
||||||
|
|
||||||
/// Error type which can be thrown by wasm code or by host environment.
|
/// Error type which can be thrown by wasm code or by host environment.
|
||||||
///
|
///
|
||||||
/// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution.
|
/// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution.
|
||||||
|
|
45
src/value.rs
45
src/value.rs
|
@ -746,27 +746,48 @@ impl_integer!(u32);
|
||||||
impl_integer!(i64);
|
impl_integer!(i64);
|
||||||
impl_integer!(u64);
|
impl_integer!(u64);
|
||||||
|
|
||||||
|
// Use std float functions in std environment.
|
||||||
|
// And libm's implementation in no_std
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
macro_rules! call_math {
|
||||||
|
($op:ident, $e:expr, $fXX:ident, $FXXExt:ident) => {
|
||||||
|
$fXX::$op($e)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
macro_rules! call_math {
|
||||||
|
($op:ident, $e:expr, $fXX:ident, $FXXExt:ident) => {
|
||||||
|
::libm::$FXXExt::$op($e)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// We cannot call the math functions directly, because there are multiple available implementaitons in no_std.
|
||||||
|
// In std, there are only `Value::$op` and `std::$fXX:$op`.
|
||||||
|
// The `std` ones are preferred, because they are not from a trait.
|
||||||
|
// For `no_std`, the implementations are `Value::$op` and `libm::FXXExt::$op`,
|
||||||
|
// both of which are trait implementations and hence ambiguous.
|
||||||
|
// So we have to use a full path, which is what `call_math!` does.
|
||||||
macro_rules! impl_float {
|
macro_rules! impl_float {
|
||||||
($type:ident, $fXX:ident, $iXX:ident) => {
|
($type:ident, $fXX:ident, $FXXExt:ident, $iXX:ident) => {
|
||||||
impl Float<$type> for $type {
|
impl Float<$type> for $type {
|
||||||
fn abs(self) -> $type {
|
fn abs(self) -> $type {
|
||||||
$fXX::abs(self.into()).into()
|
call_math!(abs, $fXX::from(self), $fXX, $FXXExt).into()
|
||||||
}
|
}
|
||||||
fn floor(self) -> $type {
|
fn floor(self) -> $type {
|
||||||
$fXX::floor(self.into()).into()
|
call_math!(floor, $fXX::from(self), $fXX, $FXXExt).into()
|
||||||
}
|
}
|
||||||
fn ceil(self) -> $type {
|
fn ceil(self) -> $type {
|
||||||
$fXX::ceil(self.into()).into()
|
call_math!(ceil, $fXX::from(self), $fXX, $FXXExt).into()
|
||||||
}
|
}
|
||||||
fn trunc(self) -> $type {
|
fn trunc(self) -> $type {
|
||||||
$fXX::trunc(self.into()).into()
|
call_math!(trunc, $fXX::from(self), $fXX, $FXXExt).into()
|
||||||
}
|
}
|
||||||
fn round(self) -> $type {
|
fn round(self) -> $type {
|
||||||
$fXX::round(self.into()).into()
|
call_math!(round, $fXX::from(self), $fXX, $FXXExt).into()
|
||||||
}
|
}
|
||||||
fn nearest(self) -> $type {
|
fn nearest(self) -> $type {
|
||||||
let round = self.round();
|
let round = self.round();
|
||||||
if self.fract().abs() != 0.5 {
|
if call_math!(fract, $fXX::from(self), $fXX, $FXXExt).abs() != 0.5 {
|
||||||
return round;
|
return round;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,7 +801,7 @@ macro_rules! impl_float {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn sqrt(self) -> $type {
|
fn sqrt(self) -> $type {
|
||||||
$fXX::sqrt(self.into()).into()
|
call_math!(sqrt, $fXX::from(self), $fXX, $FXXExt).into()
|
||||||
}
|
}
|
||||||
// This instruction corresponds to what is sometimes called "minNaN" in other languages.
|
// This instruction corresponds to what is sometimes called "minNaN" in other languages.
|
||||||
fn min(self, other: $type) -> $type {
|
fn min(self, other: $type) -> $type {
|
||||||
|
@ -828,7 +849,7 @@ macro_rules! impl_float {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_float!(f32, f32, i32);
|
impl_float!(f32, f32, F32Ext, i32);
|
||||||
impl_float!(f64, f64, i64);
|
impl_float!(f64, f64, F64Ext, i64);
|
||||||
impl_float!(F32, f32, i32);
|
impl_float!(F32, f32, F32Ext, i32);
|
||||||
impl_float!(F64, f64, i64);
|
impl_float!(F64, f64, F64Ext, i64);
|
||||||
|
|
Loading…
Reference in New Issue