Reputation: 490
While reading part of a book about 3D graphics I came across the following assignment:
const float vertexPositions[] = {
0.75f, 0.75f, 0.0f, 1.0f,
0.75f, -0.75f, 0.0f, 1.0f,
-0.75f, -0.75f, 0.0f, 1.0f,
};
Why is the f suffix necessary? Can the type of the literals not be determined from the type of the variable? I believe that without the f float literals are interpreted as doubles, but why when the array is clearly of type float?
Upvotes: 4
Views: 1618
Reputation: 320621
Some terminological nitpicks.
{}
(e.g. 1.0f
) are not literals, they are constants. C only has string literals and compound literals and that's it. In C 1.0
is a floating-point constant.In C language the type of the right-hand side (of an assignment or an initialization) is never influenced by the type of the left-hand side. The type of the value on the right-hand side is always determined independently. It is determined solely from how that value is specified. Left-hand side is never taken into consideration. Then, once the type of the right-hand size is known, the original value is converted to the type of the left-hand side. In other words, constant 1.0
is always a constant of type double
, even if you use it to initialize a float
object.
There's nothing incorrect with using a double
constant (like 1.0
) to initialize an object of type float
. As I said above, the double
value will be converted to float
type. However, some compilers issue a warning about that conversion, notifying the user about a possible precision loss. Specifically to subdue that warning people'd use an explicit float suffix (e.g. 1.0f
) or an explicit cast to float
(e.g. (float) 1.0
) when initializing float
objects. This does not look good, since it goes against the DRY (Don't-Repeat-Yourself) rule, but in real life this method of dealing with warnings is encountered quite often.
Upvotes: 1
Reputation: 80305
The float array initialization in your example is fine in C, as it would be if it used double
constants. For the values at hand, it would also be fine if it were a double
array initialized with float
constants, because the values at hand are exactly representable as float
. There would be no reason for a compiler to emit a warning even in this last case, although it would be strange and confusing that the developer bothered to type additional suffixes that do not match the eventual type.
In short, the author is only being explicit, which, in the case of a float
array, is good.
For arbitrary values written in decimal, you do not want to initialize float
variables with double
constants because of “double-rounding” (in which the word “double” means twice and does not refer to the type of the same name). If you initialize f1
and f2
as follows, they end up with different values, and f1
is actually the closest to the intended value 1.01161128282547:
float f1 = 1.01161128282547f;
float f2 = 1.01161128282547;
The explanation is that in the case of f2
, the decimal value 1.01161128282547 is first rounded to the nearest double
, and then to the nearest float
. These two steps introduce more error than directly rounding to the nearest float
, which is how f1
is initialized.
Upvotes: 5
Reputation: 6598
No, type of literal is never inferred. Without the f
they are double
literals, and the instruction is a conversion which may lose precision (not really in this case because all the literals are exactly represented with float too).
Same warning you get if you do
float x = 3.0;
Upvotes: 0
Reputation: 3698
Although you may not get no errors for omitting the f
it is good practice to put it and there are several reasons why, for example:
float num = 0.1;
(num == 0.1)
The evaluation will produce 0
because num
is rounded to 0.1
as a float and 0.1
in the expression is double. So they are actually not the same, although they may seem to be.
Upvotes: 0