float a = 0.7;
if(a<0.7)
The first line above takes the double
0.7
and crams it into a float
, which almost certainly has less precision (so you may lose information).
The second line upgrades the float a
to a double
(because you're comparing it with a double 0.7
, and that's one of the things C does for you) but it's too late at that point, the information is already gone.
You can see this effect with:
#include <stdio.h>
int main(void) {
float a = 0.7;
float b = 0.7f;
double c = 0.7;
printf("a %.50g\nb %.50g\nc %.50g\n", a, b, c);
return 0;
}
which generates something like:
a 0.699999988079071044921875
b 0.699999988079071044921875
c 0.69999999999999995559107901499373838305473327636719
Clearly, the double c
variable has about double the precision (which is why they're often referred to as single and double precision) than both:
- the
double 0.7
crammed into the float a
variable; and
- the
float b
variable that had the float 0.7
stored into it.
Neither of them is exactly 0.7
due to the way floating point numbers work, but the double
is closer to the desired value, hence not equal to the float
.
It's like pouring a full four-litre bucket of water into a three-litre bucket and then back again. The litre you lost in the overflow of the smaller bucket doesn't magically re-appear :-)
If you change the type of your a
to double
, or use float
literals like 0.7f
, you'll find things work more as you expect, since there's no loss of precision in that case.
The reason why you don't see the same effect in Python is because there's one underlying type for these floating point values:
>>> x = float(.7)
>>> type(x)
<class 'float'>
>>> type(.7)
<class 'float'>
From the Python docs:
There are three distinct numeric types: integers, floating point numbers, and complex numbers. In addition, Booleans are a subtype of integers. Integers have unlimited precision. Floating point numbers are usually implemented using double in C.
Hence no loss of precision in that case.
The use of double
seems to be confirmed by (slightly reformatted):
>>> import sys
>>> print(sys.float_info)
sys.float_info(
max=1.7976931348623157e+308,
max_exp=1024,
max_10_exp=308,
min=2.2250738585072014e-308,
min_exp=-1021,
min_10_exp=-307,
dig=15,
mant_dig=53,
epsilon=2.220446049250313e-16,
radix=2,
rounds=1
)
The exponents and min/max values are identical to those found in IEEE754 double precision values.