2

The program below outputs This No. is not same. Why does it do this when both numbers are the same?

void main() {
    float f = 2.7;

    if(f == 2.7) {
        printf("This No. is same");
    } else {
        printf("This No. is not same");
    }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • `float` representation is not necessarily the same as `double` representation. – chris Aug 01 '14 at 14:33
  • http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – abelenky Aug 01 '14 at 14:35
  • Neither `f` nor the double precision literal `2.7` are equal to the exact value 2.7. The is an issue of representability. – David Heffernan Aug 01 '14 at 14:43
  • Due to the discrete (steppped / incremental) nature of bits, there is always a float / double which can be written that lies between the two smallest steps. So, the constant `2.7` might not actually be represented in binary as exactly `2.7`. Also, since double has more precision than float, it would not equal bit-wise because the closest float to 2.7 is not as close as the closest double to 2.7. Basically, when dealing with floats, you need to consider the error boundaries around the number. Doubly so for float to double conversions and the like. – Edwin Buck Aug 01 '14 at 14:49
  • Type of `f` is `float`, type of `2.7` is `double`. First, in the initialization, `2.7` (of type `double`) is converted to `float` (losing some precision) and then the resulting `float` converted to `double` for the comparison. The two values (`(double)((float)2.7)` and `2.7`) may be different. – pmg May 22 '19 at 18:49

3 Answers3

7

Why does it do this when both numbers are the same?

The numbers are not the same value.

double can represent exactly typically about 264 different values.
float can represent exactly typically about 232 different values.

2.7 is not one of the values - some approximations are made given the binary nature of floating-point encoding versus the decimal text 2.7


The compiler converts 2.7 to the nearest representable double or
2.70000000000000017763568394002504646778106689453125
given the typical binary64 representation of double. The next best double is
2.699999999999999733546474089962430298328399658203125.
Knowing the exact value beyond 17 significant digits has reduced usefulness.

When the value is assigned to a float, it becomes the nearest representable float or
2.7000000476837158203125.

2.70000000000000017763568394002504646778106689453125 does not equal 2.7000000476837158203125.

Should a compiler use a float/double which represents 2.7 exactly like with decimal32/decimal64, code would work as OP expected. double representation using an underlying decimal format is rare. Far more often the underlying double representation is base 2 and these conversion artifacts need to be considered when programming.

Had the code been float f = 2.5;, the float and double value, using a binary or decimal underlying format, would have made if (f == 2.5) true. The same value as a high precision double is representable exactly as a low precision float.

(Assuming binary32/binary64 floating point)
double has 53 bits of significance and float has 24. The key is that if the number as a double has its least significant (53-24) bits set to 0, when converted to float, it will have the same numeric value as a float or double. Numbers like 1, 2.5 and 2.7000000476837158203125 fulfill that. (range, sub-normal, and NaN issues ignored here.)

This is a reason why exact floating point comparisons are typically only done in select situations.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

Check this program:

 #include<stdio.h>
 int main()
{
   float x = 0.1;
    printf("%zu %zu %zu\n", sizeof(x), sizeof(0.1), sizeof(0.1f));
    return 0;
}

Output is 4 8 4.

The values used in an expression are considered as double (double precision floating point format) unless a f is specified at the end. So the expression “x==0.1″ has a double on right side and float which are stored in a single precision floating point format on left side.

In such situations float is promoted to double . The double precision format uses uses more bits for precision than single precision format.

In your case add 2.7f to get expected result.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
vinay hunachyal
  • 3,781
  • 2
  • 20
  • 31
0

The literal 2.7 in f == 2.7 is converted to double that's why 2.7 is not equal to f.

haccks
  • 104,019
  • 25
  • 176
  • 264