The C standard says in 6.5:
A floating expression may be contracted, that is, evaluated as
though it were a single operation, thereby omitting rounding errors
implied by the source code and the expression evaluation method.
with the following note:
The intermediate operations in the contracted expression are
evaluated as if to infinite range and precision, while the final
operation is rounded to the format determined by the expression
evaluation method. [...]
But it says nothing about casts, which are explicit conversion
operations that normally remove any intermediate extended precision,
as if they were assimilated to a real rounding operation (rather
than something that would just give an additional rounding error),
just like the rint() function.
So my question is:
In the following code
volatile double a = 0x1.00000001p+0;
volatile double b = -1.0;
printf ("%a\n", (double) (a * a) + b);
printf ("%a\n", (float) (a * a) + b);
may the (double) (a * a) + b and (float) (a * a) + b FP expressions
be contracted with the use of a FMA, i.e. as if fma(a,a,b) were used?
Based on my above remark, I would say "no".
But GCC (at least until a 14.0.0 20231017 snapshot), Clang (at least
until version 17) and Intel's oneAPI compiler 2021.3.0.20210619 all
contract (double) (a * a) + b with the use of a FMA; thus they output 0x1.000000008p-31 instead of 0x1p-31.
However, these compilers do not contract (float) (a * a) + b:
they output 0x1p-31. It is rather surprising that they treat it
differently.
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 991 |
Nodes: | 10 (0 / 10) |
Uptime: | 81:35:43 |
Calls: | 12,949 |
Calls today: | 3 |
Files: | 186,574 |
Messages: | 3,264,673 |