From d082f24a2d4da1eddb9904245a908e3aa18fc2d2 Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:52:39 -0400 Subject: [PATCH] Fix rounding of fixed-point constants where fractional digits should carry into integer part (#2088) --- src/asm/lexer.cpp | 16 +++++++++++----- test/asm/fixed-point-carry.asm | 17 +++++++++++++++++ test/asm/fixed-point-carry.err | 6 ++++++ test/asm/fixed-point-carry.out | 12 ++++++++++++ test/asm/fixed-point-syntax.out | 4 ++-- 5 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 test/asm/fixed-point-carry.asm create mode 100644 test/asm/fixed-point-carry.err create mode 100644 test/asm/fixed-point-carry.out diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index 27b0b76f..8607ecf4 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -1005,14 +1005,20 @@ static uint32_t finishReadingFixedPoint(uint32_t integer) { precision = options.fixPrecision; } - if (integer >= (1ULL << (32 - precision))) { - warning(WARNING_LARGE_CONSTANT, "Magnitude of fixed-point constant is too large"); - return 0; - } - // Cast to unsigned avoids undefined overflow behavior uint32_t fractional = static_cast(round(static_cast(dividend) / divisor * (1ULL << precision))); + // Carry from `fractional` to `integer` if `round` rounded up to the next integer + assume(fractional <= 1ULL << precision); + if (fractional == 1ULL << precision) { + ++integer; + fractional = 0; + } + + if (integer >= 1ULL << (32 - precision)) { + warning(WARNING_LARGE_CONSTANT, "Magnitude of fixed-point constant is too large"); + return 0; + } return (integer << precision) | fractional; } diff --git a/test/asm/fixed-point-carry.asm b/test/asm/fixed-point-carry.asm new file mode 100644 index 00000000..b8b2ffad --- /dev/null +++ b/test/asm/fixed-point-carry.asm @@ -0,0 +1,17 @@ +opt Q8 +println strfmt("%f", 1.999) +println strfmt("%f", 2.999) +println strfmt("%f", 3.999) +println strfmt("%f", 16777215.999) + +opt Q16 +println strfmt("%f", 1.999999) +println strfmt("%f", 2.999999) +println strfmt("%f", 3.999999) +println strfmt("%f", 65535.999999) + +opt Q24 +println strfmt("%f", 1.999999999) +println strfmt("%f", 2.999999999) +println strfmt("%f", 3.999999999) +println strfmt("%f", 255.999999999) diff --git a/test/asm/fixed-point-carry.err b/test/asm/fixed-point-carry.err new file mode 100644 index 00000000..c51cab0c --- /dev/null +++ b/test/asm/fixed-point-carry.err @@ -0,0 +1,6 @@ +warning: Magnitude of fixed-point constant is too large [-Wlarge-constant] + at fixed-point-carry.asm(5) +warning: Magnitude of fixed-point constant is too large [-Wlarge-constant] + at fixed-point-carry.asm(11) +warning: Magnitude of fixed-point constant is too large [-Wlarge-constant] + at fixed-point-carry.asm(17) diff --git a/test/asm/fixed-point-carry.out b/test/asm/fixed-point-carry.out new file mode 100644 index 00000000..da557e77 --- /dev/null +++ b/test/asm/fixed-point-carry.out @@ -0,0 +1,12 @@ +2.00000 +3.00000 +4.00000 +0.00000 +2.00000 +3.00000 +4.00000 +0.00000 +2.00000 +3.00000 +4.00000 +0.00000 diff --git a/test/asm/fixed-point-syntax.out b/test/asm/fixed-point-syntax.out index 60f49483..36da8610 100644 --- a/test/asm/fixed-point-syntax.out +++ b/test/asm/fixed-point-syntax.out @@ -5,9 +5,9 @@ $18B $62B85 $4 $10000 +$20000 $10000 -$10000 -$10000 +$20000 $C570A $13333 $13333