From 2e2c4b470a8a6b7eb4ee84a595b3fde3fadabcdf Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 17 Jan 2026 16:36:44 +0200 Subject: [PATCH] math: fix edge cases of round_to_even(), add tests (#26380) --- vlib/math/floor.v | 13 +++++++++++-- vlib/math/floor_test.v | 11 +++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/vlib/math/floor.v b/vlib/math/floor.v index fb6110844..b2f6fd6fa 100644 --- a/vlib/math/floor.v +++ b/vlib/math/floor.v @@ -143,8 +143,8 @@ pub fn round_to_even(x f64) f64 { // number is even or odd (respectively). half_minus_ulp := u64(u64(1) << (shift - 1)) - 1 e_ -= u64(bias) - bits += (half_minus_ulp + (bits >> (shift - e_)) & 1) >> e_ - bits &= ~(frac_mask >> e_) + bits += safe_shift(half_minus_ulp + safe_shift(bits, shift - e_) & 1, e_) + bits &= ~safe_shift(frac_mask, e_) } else if e_ == bias - 1 && bits & frac_mask != 0 { // round 0.5 < abs(x) < 1. bits = bits & sign_mask | uvone // +-1 @@ -154,3 +154,12 @@ pub fn round_to_even(x f64) f64 { } return f64_from_bits(bits) } + +@[inline] +fn safe_shift(value u64, shift u64) u64 { + return if shift > u64(63) { + u64(0) + } else { + value >> shift + } +} diff --git a/vlib/math/floor_test.v b/vlib/math/floor_test.v index e6c5ddf06..541b595ca 100644 --- a/vlib/math/floor_test.v +++ b/vlib/math/floor_test.v @@ -4,3 +4,14 @@ fn test_round_to_even() { assert math.round_to_even(0.123) == 0.0 assert math.round_to_even(123.12345) == 123.00 } + +fn test_rount_to_even_edge() { + vrounds_ := [f64(-0.0), 0.0, -0.5, 0.5, -1.0, 1.0, 0.12345, 1.2345, 12.345, 123.45, 1234.5, + 12345.0, -math.pi, math.pi, math.inf(-1), math.inf(1), + math.nan()] + rounds_ := [f64(0.0), 0.0, -0.0, 0.0, -1.0, 1.0, 0.0, 1.0, 12.0, 123.0, 1234.0, 12345, -3.0, + 3.0, math.inf(-1), math.inf(1), math.nan()] + for i, v in vrounds_ { + assert math.alike(math.round_to_even(v), rounds_[i]) + } +} -- 2.39.5