From c7867f7ae4f0d8dbcadcf88b2886885c9ba9fa13 Mon Sep 17 00:00:00 2001 From: Shaisolaris <66793913+Shaisolaris@users.noreply.github.com> Date: Mon, 12 Oct 2026 00:25:33 -0700 Subject: [PATCH] Round away from zero in ROUND_UP for values far below the rounding position VpMidRound zeroed the value whenever the rounding position was left of the first digit word, except for ROUND_CEILING and ROUND_FLOOR. ROUND_UP also rounds any nonzero remainder away from zero, so it gave 0 instead of the next unit, e.g. BigDecimal("1e-10").round(0, :up) returned 0 while BigDecimal("1e-7").round(0, :up) returned 1. --- ext/bigdecimal/bigdecimal.c | 2 +- test/bigdecimal/test_bigdecimal.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index e934e340..51d88c2a 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -5888,7 +5888,7 @@ VpMidRound(Real *y, unsigned short f, ssize_t nf) exptoadd=0; if (nf < 0) { /* rounding position too left(large). */ - if (f != VP_ROUND_CEIL && f != VP_ROUND_FLOOR) { + if (f != VP_ROUND_UP && f != VP_ROUND_CEIL && f != VP_ROUND_FLOOR) { VpSetZero(y, VpGetSign(y)); /* truncate everything */ return 0; } diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb index a24bdbcc..04d9f900 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -1560,6 +1560,18 @@ def test_round assert_instance_of(BigDecimal, x.round(1)) end + def test_round_up_value_far_below_rounding_position + ["1e-10", "1e-27", "0.942882777e-12"].each do |s| + x = BigDecimal(s) + assert_equal(1, x.round(0, BigDecimal::ROUND_UP), s) + assert_equal(-1, (-x).round(0, BigDecimal::ROUND_UP), s) + assert_equal(BigDecimal("0.000001"), x.round(6, :up), s) + assert_equal(BigDecimal("-0.000001"), (-x).round(6, :up), s) + assert_equal(1000, x.round(-3, :up), s) + assert_equal(x.ceil(6), x.round(6, :up), s) + end + end + def test_round_half_even assert_equal(BigDecimal('12.0'), BigDecimal('12.5').round(half: :even)) assert_equal(BigDecimal('14.0'), BigDecimal('13.5').round(half: :even))