Since in C/C++ floating-point literals without a suffix default to type double , then assigning such a literal to a float performs an implicit conversion from double to float .
float n = 3.14;
if(n == 3.14f)
puts("Igual");
This does not print the message instead if we add the suffix f to 3.14 in the declaration of n to prevent the conversion if printed. The question is, is there a loss of precision when the conversion is carried out?
Ask
Yes, there is a loss of precision.
Narrowing . _
The floating point data types are:
float
: Single precision. They are usually a 32-bit wide type following IEEE-754 32-bit.double
- Double precision. They are usually a 64-bit wide type following IEEE-754 64-bit.long double
- Extended accuracy. They are usually an 80-bit type on 32-bit and 64-bit architectures. Does not necessarily follow IEEE-754 .Every time you go from a type of higher precision to one of less, a narrowing occurs; data can be lost every time a narrowing occurs, when does this happen?
Type conversion.
According to the C standard in the
§6.3.1.5
Real Floating Point Types section (translation and emphasis mine):In your case, assigning the value
3.14
to afloat
corresponds to a narrowing, but since the value is exactly3.14
representable by the value will not change.float
What is failing?
If the value has not changed, why does your code fail?:
Because I lied, the value
3.14
is NOT representable byfloat
exactly. There are floating point numbers that are not exactly representable in binary, this is due to the properties of each base 1 .The value 3.14 in binary is not exactly representable and with double precision its value is approximately 3.140000000000000 12434497875802 but by storing it in a
float
you have lost some precision, how much exactly? It will depend on your system...So you will be comparing a number like the truncation of the value
double
3.14000000000000012434497875802 against a number like3.14f
that in many cases will not be the same number. For example the literal 3.14 in float is approximately 3.140000 1049041748046875 so your comparison would be, more or less:That obviously does not comply with equality.
It's terrible! What I can do?
As eferion comments , you should avoid comparing floating point numbers by equality, due to rounding errors you should compare them by almost equality , a function like this could help you:
FLT_EPSILON
The and valuesDBL_EPSILON
are the difference between 1 and the next value representable byfloat
anddouble
respectively; in other words, they are approximately the smallest value representable by each of the types, so if the difference betweenizquierda
andderecha
is less than or equal to this value, both values are almost equal .1 For example, 1/3 in base 10 is a pure periodic number of value 0.3333333... while in base 12 it is exactly 0.4. In decimal the value 1/10 is exactly 0.1 but in binary it is a mixed periodic number of value 0.00011001100110011...
Floating point numbers should never ever be compared using the comparison operator.
The reason is that these numbers have a certain precision, the rest of the digits being practically random.
The correct way is to perform the comparison assuming a certain margin of error:
You can play with the precision to adapt it to your needs. The example is simply illustrative.
All the best
Here is a very illustrative example of what happens. And it really is worth explaining.
You have two uninitialized memory areas like so:
Area A:
Area B:
Then you put a
float
in A:And one
double
in B:So by comparing A to B, you get the comparison of:
With
Being these different. I hope it was educational for you.