cranelift: Use round_ties_even for nearest in interpreter (#4413)

As @MaxGraey pointed out (thanks!) in #4397, `round` has different
 behavior from `nearest`. And it looks like the native rust
 implementation is still pending stabilization.

 Right now we duplicate the wasmtime implementation, merged in #2171.

 However, we definitely should switch to the rust native version
 when it is available.
This commit is contained in:
Afonso Bordado
2022-07-08 00:36:43 +01:00
committed by GitHub
parent a8ce7f123b
commit 16cb287c53
6 changed files with 141 additions and 7 deletions

View File

@@ -816,9 +816,20 @@ impl Ieee32 {
Self::with_float(self.as_f32().trunc())
}
/// Returns the nearest integer to `self`. Round half-way cases away from `0.0`.
pub fn nearest(self) -> Self {
Self::with_float(self.as_f32().round())
/// Returns the nearest integer to `self`. Rounds half-way cases to the number
/// with an even least significant digit.
pub fn round_ties_even(self) -> Self {
// TODO: Replace with the native implementation once
// https://github.com/rust-lang/rust/issues/96710 is stabilized
let toint_32: f32 = 1.0 / f32::EPSILON;
let f = self.as_f32();
let e = self.0 >> 23 & 0xff;
if e >= 0x7f_u32 + 23 {
self
} else {
Self::with_float((f.abs() + toint_32 - toint_32).copysign(f))
}
}
}
@@ -965,9 +976,20 @@ impl Ieee64 {
Self::with_float(self.as_f64().trunc())
}
/// Returns the nearest integer to `self`. Round half-way cases away from `0.0`.
pub fn nearest(self) -> Self {
Self::with_float(self.as_f64().round())
/// Returns the nearest integer to `self`. Rounds half-way cases to the number
/// with an even least significant digit.
pub fn round_ties_even(self) -> Self {
// TODO: Replace with the native implementation once
// https://github.com/rust-lang/rust/issues/96710 is stabilized
let toint_64: f64 = 1.0 / f64::EPSILON;
let f = self.as_f64();
let e = self.0 >> 52 & 0x7ff_u64;
if e >= 0x3ff_u64 + 52 {
self
} else {
Self::with_float((f.abs() + toint_64 - toint_64).copysign(f))
}
}
}