84

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.

12
  • 34
    There's -Wdouble-promotion, which will at least give you warnings. Combined with -Wfloat-conversion should give pretty good coverage.
    – Brett Hale
    Commented Aug 28, 2015 at 8:47
  • 3
    This doesn't directly answer your question, but it wouldn't be that difficult to write a script to just insert any missing fs from FP literals. Commented Aug 28, 2015 at 8:47
  • 1
    Does this help: stackoverflow.com/questions/24688911/… ? Commented Aug 28, 2015 at 8:49
  • 4
    Some compilers for embedded systems map double to float and only enable double precision with an option. I don't know if there are something similar in GCC
    – phuclv
    Commented Aug 28, 2015 at 8:56
  • 3
    @BrettHale That comment is worthy of being an proper answer. I think that getting warnings in this case would be more productive, than some other compiler option that allows programmer to write code that's not compatible with the standard.
    – user694733
    Commented Aug 28, 2015 at 11:36

4 Answers 4

89

-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.

2
  • 2
    Thanks! I didn't know about this flag. This answers my question perfectly - even though, as other suggested, generating warnings would perhaps be more prudent.
    – Zeus
    Commented Aug 31, 2015 at 2:35
  • 2
    I would use this option wisely! Consider a new developer, just typing 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.
    – math
    Commented Sep 4, 2015 at 7:47
59

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.

6
  • You are right in general, of course. However, in my specific circumstances -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.
    – Zeus
    Commented Aug 31, 2015 at 2:32
  • 4
    I, too, believe that it is dangerous to just hide a problem that is in your source code using a command switch. Just consider that your code might be used by someone else five years from now using a new version of the compiler, maybe not having that neat switch. It is much preferable to fix the problems in the source code than to hide them. And about all these warnings... when compiling for production, warnings should be considered errors. -Werror :-)
    – Chrissi
    Commented Sep 2, 2015 at 6:26
  • there's nothing smart about forcing yourself to write f at the end of every number literal,
    – 12Me21
    Commented Mar 3, 2021 at 3:39
  • @12Me21 : look at the asm output of: 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'.
    – Brett Hale
    Commented Mar 3, 2021 at 9:25
  • oh I just meant, I feel like -fsingle-precision-constant is a better solution here. same result with less effort.
    – 12Me21
    Commented Mar 4, 2021 at 5:07
2

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) ...
2
  • Or cast them in the definition, as in #define foo ((float) 1.234) Commented Sep 3, 2015 at 14:10
  • 3
    @CuriousRabbit: that doesn't address the "a less disciplined (or just new) developer" issue.
    – user1196549
    Commented Sep 3, 2015 at 14:19
2

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...

1
  • I second this. The other answers would not warn when a sole double-precision calculation is performed. So if no conversion or promotion is done. E.g. if (1.01 * 1.0 >= 1.0) { ... }. Your solution does.
    – rzickler
    Commented May 31 at 8:20

Not the answer you're looking for? Browse other questions tagged or ask your own question.