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

            Bug ID: 97635
           Summary: binary-to-DFP conversions incorrect
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libgcc
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jsm28 at gcc dot gnu.org
  Target Milestone: ---

On targets using DPD decimal floating point (tested for powerpc64le-linux-gnu,
presumably applies on s390 as well), the libgcc conversions from binary
floating point to decimal floating point, using sprintf, are not correctly
rounded.  IEEE 754 requires such conversions to be correctly rounded (using the
decimal rounding mode, not the binary rounding mode), with corresponding
exceptions (and the lowest possible decimal quantum exponent if the result is
inexact, the quantum exponent as close to 0 as possible if the result is
exact).

sprintf is used with BFP_FMT, where BFP_FMT is set to use a precision depending
on the source format.  However, that precision is the solution to a different
problem: what precision is sufficient for (to-nearest) conversion from that
binary format to decimal and back to produce the same binary value (i.e. the
precisions are the values of FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, etc.).  The
problem here isn't converting to decimal and back, it's converting correctly to
a given decimal format, where exactly one value in that format is a correct
result, and other values that round back to the same binary value are
incorrect.

For example, the test below, which fails for powerpc64le-linux-gnu, does a
conversion from float to _Decimal64.  Unsurprisingly, a 9-digit decimal value
from sprintf is not sufficient for a correctly rounded 16-digit _Decimal64
value.  Using the precision of the *target* type, not the source type, would
mostly work if sprintf is correctly rounding, except that the result needs to
be rounded according to the decimal rounding mode and sprintf for a binary
input rounds according to the binary rounding mode (and the case of "to
nearest, ties away from 0" doesn't have a corresponding binary mode, even if
you restrict attention to the IEEE decimal modes and ignore the other ones
supported on Power hardware), and also there would be problems with double
rounding and missing underflow exceptions when the result is in the subnormal
range for the decimal format (there could be problems with decimal quantum
exponents as well).

extern void abort (void);
extern void exit (int);

float f = 0.1f;

_Decimal64 d = 0.1000000014901161DD;
_Decimal64 dd = (_Decimal64) 0.1f;

int
main (void)
{
  /* Compile-time conversion is correct.  */
  if (dd != d)
    abort ();
  /* Run-time conversion is incorrect.  */
  if ((_Decimal64) f != d)
    abort ();
  exit (0);
}

Reply via email to