It is well known that in C, floating point literals (e.g. 1.23
) have type double
. As a consequence, any calculation that involves them is promoted to double.
I'm working on an embedded real-time system that has a floating point unit that supports only single precision (float
) numbers. All my variables are float
, and this precision is sufficient. I don't need (nor can afford) double
at all. But every time something like
if (x < 2.5) ...
is written, disaster happens: the slowdown can be up to two orders of magnitude. Of course, the direct answer is to write
if (x < 2.5f) ...
but this is so easy to miss (and difficult to detect until too late), especially when a 'configuration' value is #define
'd in a separate file by a less disciplined (or just new) developer.
So, is there a way to force the compiler to treat all (floating point) literals as float, as if with suffix f
? Even if it's against the specs, I don't care. Or any other solutions? The compiler is gcc, by the way.
-Wdouble-promotion
, which will at least give you warnings. Combined with -Wfloat-conversion
should give pretty good coverage.
f
s from FP literals.
-fsingle-precision-constant
flag can be used. It causes floating-point constants to be loaded in single precision even when this is not exact.
Note- This will also use single precision constants in operations on double precision variables.
Use warnings instead: -Wdouble-promotion
warns about implicit float to double promotion, as in your example. -Wfloat-conversion
will warn about cases where you may still be assigning doubles to floats.
This is a better solution than simply forcing double values to the nearest float value. Your floating-point code is still compliant, and you won't get any nasty surprises if a double value holds a positive value, say, less than FLT_DENORM_MIN
(assuming IEEE-754) or greater than FLT_MAX
.
-fsingle-precision-constant
works better. First, my version of GCC (4.4.7) simply doesn't have either of these options. Second, I don't have any tricky constants (apart from NaN), and all calculations must be float
anyway (this is the whole point). Finally, the supplied chip library generates so many warnings (most of them explicit!) that the useful ones often get buried in the pile... And, as I said, I'm not very concerned about strict compliance in this case.
f
at the end of every number literal,
float fn (float x) { return (x * 1.2); }
vs (1.2f)
- the expression is forced to be evaluated as a double and then converted back to a float. It's not a question of being 'smart'.
You can cast the defined constants to (float)
wherever they are used, the optimizer should do its job. This is a portable solution.
#define LIMIT 2.5
if (x < (float)LIMIT) ...
The -Wunsuffixed-float-constants
flag could be used too, maybe combined with some of the other options in the accepted answer above. However, this probably won't catch unsuffixed constants in system headers. Would need to use -Wsystem-headers
to catch those too. Could generate a lot of warnings...
Success story sharing
x < 2.5
, everything will be okay. He is likely to miss that specific compiler option which saves his life :-). When he is getting warnings instead (with-Wdouble-promotion
,-Wfloat-conversion
), and you use-Werror
which converts all warnings into errors, he may not directly checkin the code, and might wonder, and learn. But just for release quality, you might want to play safe, and compile it with the specific option (-fsingle-precision-constant
). Please note this is just a comment.