core: Improve performance of round_to_even

This patch improves performance of ecma_conversions::round_to_even():
1. by using f64::round_ties_even(), which has been stable
   since 1.77.0, instead of a custom algorithm; and
2. by removing an unnecessary comparison to i32::MIN,
   as casting a float to an integer automatically saturates
   values smaller than the minimum integer value to the minimum
   value of the integer type.
This commit is contained in:
Kamil Jarosz 2024-05-08 12:55:03 +02:00 committed by Adrian Wielgosik
parent 8eaf844cdc
commit bc4ed4c5a1
1 changed files with 2 additions and 8 deletions

View File

@ -45,17 +45,11 @@ pub fn f64_to_wrapping_i32(n: f64) -> i32 {
/// Implements the IEEE-754 "Round to nearest, ties to even" rounding rule. /// Implements the IEEE-754 "Round to nearest, ties to even" rounding rule.
/// (e.g., both 1.5 and 2.5 will round to 2). /// (e.g., both 1.5 and 2.5 will round to 2).
/// Although this is easy to do on most architectures, Rust provides no standard
/// way to round in this manner (`f64::round` always rounds away from zero).
/// For more info and the below code snippet, see: https://github.com/rust-lang/rust/issues/55107
/// This also clamps out-of-range values and NaN to `i32::MIN`. /// This also clamps out-of-range values and NaN to `i32::MIN`.
/// TODO: Investigate using SSE/wasm intrinsics for this.
pub fn round_to_even(n: f64) -> i32 { pub fn round_to_even(n: f64) -> i32 {
let k = 1.0 / f64::EPSILON; let out = n.round_ties_even();
let a = n.abs();
let out = if a < k { ((a + k) - k).copysign(n) } else { n };
// Clamp out-of-range values to `i32::MIN`. // Clamp out-of-range values to `i32::MIN`.
if out.is_finite() && out >= i32::MIN.into() && out <= i32::MAX.into() { if out.is_finite() && out <= i32::MAX.into() {
out as i32 out as i32
} else { } else {
i32::MIN i32::MIN