Question
For a C99 compiler implementing exact IEEE 754 arithmetic, do values of f
, divisor
of type float
exist such that f / divisor != (float)(f * (1.0 / divisor))
?
EDIT: By “implementing exact IEEE 754 arithmetic” I mean a compiler that rightfully defines FLT_EVAL_METHOD as 0.
Context
A C compiler that provides IEEE 754-compliant floating-point can only replace a single-precision division by a constant by a single-precision multiplication by the inverse if said inverse is itself representable exactly as a float
.
In practice, this only happens for powers of two. So a programmer, Alex, may be confident that f / 2.0f
will be compiled as if it had been f * 0.5f
, but if it is acceptable for Alex to multiply by 0.10f
instead of dividing by 10, Alex should express it by writing the multiplication in the program, or by using a compiler option such as GCC's -ffast-math
.
This question is about transforming a single-precision division into a double-precision multiplication. Does it always produce the correctly rounded result? Is there a chance that it could be cheaper, and thus be an optimization that compilers might make (even without -ffast-math
)?
I have compared (float)(f * 0.10)
and f / 10.0f
for all single-precision values of f
between 1 and 2, without finding any counter-example. This should cover all divisions of normal float
s producing a normal result.
Then I generalized the test to all divisors with the program below:
#include <float.h>
#include <math.h>
#include <stdio.h>
int main(void){
for (float divisor = 1.0; divisor != 2.0; divisor = nextafterf(divisor, 2.0))
{
double factor = 1.0 / divisor; // double-precision inverse
for (float f = 1.0; f != 2.0; f = nextafterf(f, 2.0))
{
float cr = f / divisor;
float opt = f * factor; // double-precision multiplication
if (cr != opt)
printf("For divisor=%a, f=%a, f/divisor=%a but (float)(f*factor)=%a\n",
divisor, f, cr, opt);
}
}
}
The search space is just large enough to make this interesting (246). The program is currently running. Can someone tell me whether it will print something, perhaps with an explanation why or why not, before it has finished?
+=FLT_EPSILON
instead ofnextafterf
. – R.. GitHub STOP HELPING ICEgcc -O2
andclang -O2
generate the function call fornextafterf()
. – Pascal Cuoq