M
Mark Dickinson
I'm dealing with some code that (for the purposes of serialization)
explicitly
casts a double to a float. In essence, it looks like this:
#include <math.h>
#include <stdio.h>
void f(double x) {
float y = x;
if (isinf(y) && !isinf(x))
printf("Deal with overflow here\n");
else
printf("Do something with %.17g\n", y);
}
However, according to C99 6.3.1.5p2, converting a finite value that's
"outside
the range of values that can be represented" as a float gives
undefined behaviour.
How would you rewrite the above to avoid undefined behaviour? The
obvious
solution is to check whether fabs(x) > FLT_MAX before converting.
But:
This isn't quite the same thing, since some values that are *only
just* greater
than FLT_MAX would normally be expected to round down to FLT_MAX, so
the
boundary is actually something like (assuming IEEE 754 floats and
doubles)
FLT_MAX / (1 - 0.5 * FLT_EPSILON) * (1 - 0.25 * FLT_EPSILON)
So the question is: what's the exact meaning of "outside the range of
values
that can be represented" in C99 6.3.1.5p2? For converting from double
to
float, is the relevant range only up to (and including) FLT_MAX, or
can I
assume that I'm safe all the way up to (but not including) the
slightly larger
bound above?
(Note: on the platforms I care about, it's realistic to assume that
double
and float are IEEE 754 binary64 and binary32 formats, respectively,
and
that conversion from double to float uses round-half-to-even.)
explicitly
casts a double to a float. In essence, it looks like this:
#include <math.h>
#include <stdio.h>
void f(double x) {
float y = x;
if (isinf(y) && !isinf(x))
printf("Deal with overflow here\n");
else
printf("Do something with %.17g\n", y);
}
However, according to C99 6.3.1.5p2, converting a finite value that's
"outside
the range of values that can be represented" as a float gives
undefined behaviour.
How would you rewrite the above to avoid undefined behaviour? The
obvious
solution is to check whether fabs(x) > FLT_MAX before converting.
But:
This isn't quite the same thing, since some values that are *only
just* greater
than FLT_MAX would normally be expected to round down to FLT_MAX, so
the
boundary is actually something like (assuming IEEE 754 floats and
doubles)
FLT_MAX / (1 - 0.5 * FLT_EPSILON) * (1 - 0.25 * FLT_EPSILON)
So the question is: what's the exact meaning of "outside the range of
values
that can be represented" in C99 6.3.1.5p2? For converting from double
to
float, is the relevant range only up to (and including) FLT_MAX, or
can I
assume that I'm safe all the way up to (but not including) the
slightly larger
bound above?
(Note: on the platforms I care about, it's realistic to assume that
double
and float are IEEE 754 binary64 and binary32 formats, respectively,
and
that conversion from double to float uses round-half-to-even.)