https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116319

            Bug ID: 116319
           Summary: std::fma should compute as if to infinite precision
                    and rounded only once to fit the result type.
           Product: gcc
           Version: 14.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: shihyente at hotmail dot com
  Target Milestone: ---

Hi,

Let's use std::bfloat16_t in <stdfloat> to create an example.

Consider 2.375^2 + 2^-133, given there is a small subnormal offset (2^-133), if
we make the output round to the nearest, then it should be 5.65625 in
std::bfloat16_t, but the result is 5.625.

We know 2.375 * 2.375 = 5.640625, which is the middle point of 5.625 and
5.65625 as (5.625 + 5.65625) / 2 = 5.640625.

A small positive offset should make it round to 5.65625 even if we make halfway
cases to even because it is not the true halfway due to infinite precision.

The command and code to reproduce it

g++ -std=c++23 -Wall -Wextra -Werror -O0 test.cpp

#include <cfenv>
#include <cstdint>
#include <cmath>
#include <bit>
#include <stdfloat>
#include <iostream>
#include <iomanip>

using namespace std;

int main() {
    fesetround(FE_TONEAREST);  // rounding to nearest (halfway cases to even)

    const auto b = bit_cast<bfloat16_t>((uint16_t)0x4018); // 2.375
    const auto c = bit_cast<bfloat16_t>((uint16_t)0x1); // 2^-133
    const auto d = fma(b, b, c);
    cout << static_cast<double>(d) << "\n";
    cout << "0x" << hex << setfill('0') << bit_cast<uint16_t>(d) << "\n"; 
}


Best,
John

Reply via email to