Mohamed Abdullah
Mohamed Abdullah

Reputation: 33

Similar codes output different results

The output of the following code is 0.0000000:

#include <stdio.h>

int main() {
    float x;
    x = (float)3.3 == 3.3;

    printf("%f", x);

    return 0;
}

Whereas this code outputs 1.000000:

int main() { 
    float x; 
    x = (float)3.5 == 3.5; 

    printf("%f", x); 

    return 0; 
} 

The only difference between the 2 codes is the value in the comparison, however, the results are not the same, why is this?

Upvotes: 2

Views: 136

Answers (7)

anastaciu
anastaciu

Reputation: 23832

float has less precision than double, the value of 3.3 constant defaults to double and is 3.299999999999999822, the same constant when converted to float is 3.29999995231628418.

3.299999999999999822 == 3.29999995231628418 the result of this comparison is false i.e. 0.

Given the precedence rules, the expresssion amounts to x = ((float)3.5 == 3.5);, the comparison is evaluated first and the result is assigned to x.

When there is no cast both constants default to double so naturally the result of the comparison between them is true i.e. 1.

Regarding the comparison between 3.5 double and float being true, it has to do with the binary conversion, 3.3 is subjected to an aproximation given the fact that the mantissa conversion would go on indefinitely as can be seen in the link above, the exact value simply cannot be represented in double nor in float, whereas 3.5 is perfectly representable both in double and float alike.

Upvotes: 2

Rohan Bari
Rohan Bari

Reputation: 7726

The assigned value 3.3 is a type of double but you're trying to compare a double with a float (by typecasting and due to this, precision losses).

The value of 3.3 as double is 3.299999999999999822 whereas the same value in float is measured 3.299999952F which are clearly unequal. Hence, the result will be true (i.e. 1.0000000) if you typecast the other 3.3 as float.

Rather than:

x = (float) 3.3 == 3.3; // float != double precision (precision loss)

If you do this:

x = (float) 3.3 == (float) 3.3; // converting both to make precision equal

Or,

x = (double) 3.3 == (double) 3.3; // converting . . . (same)

In other words, the comparison will be equal if you convert any one of the expression as same as the other one.

Also, notice that 3.5 is equal to 3.50000000... in both float and double, hence all the trailing zeroes are truncated from the assigned variable and hence you get 1.0000000. But this stuff is just a bit contrary with 3.3.

Upvotes: 2

John Bode
John Bode

Reputation: 123578

Values like 3.3 cannot be represented exactly in a finite number of bits, just like the result of 1/3 cannot be represented exactly in a finite number of decimal digits, so you wind up storing an approximation of the value.

The float approximation is different from the double approximation, so the comparison (float) 3.3 == 3.3 fails.

By contrast, 3.5 can be represented exactly in both float and double types, so the comparison (float) 3.5 == 3.5 succeeds.

Just like with integer types, the significand of a floating-point type is a sum of powers of 2 - the value 3.5 is represented as 1.75 * 21, and the binary representation of the significand 1.75 is 1.112 - 1 * 20 + 1 * 2-1 + 1 * 2-2, or 1 + 0.5 + 0.25.

Upvotes: 1

pmg
pmg

Reputation: 108988

3.3 in binary is

11.0100110011001100110011001100110011001100110011

When converted to float some bits of precision are truncated

11.0100110011001100110011001100110

When converted back to double, computer just uses 0's

11.0100110011001100110011001100110000000000000000

So

3.3                     11.0100110011001100110011001100110011001100110011
(float)3.3              11.0100110011001100110011001100110
(double)((float)3.3)    11.0100110011001100110011001100110000000000000000

3.5 for comparison

3.5                     11.1000000000000000000000000000000000000000000000
(float)3.5              11.1000000000000000000000000000000
(double)((float)3.5)    11.1000000000000000000000000000000000000000000000

Upvotes: 1

Stephan Lechner
Stephan Lechner

Reputation: 35164

The issue is that you loose precision when converting the value 3.3, which is a literal of type double, to a float value with the cast (float)3.3. This loss of precision is irreversible, even if the comparison operator == will promote the left operand back to type double.

So the issue is that

(double)((float)3.3) == (double)3.3

will be false since the cast of 3.3 to float looses precision. For 3.5, in contrast, the result will be true, because 3.5 can be exactly represented as float in the same precision as double can.

Actually, the situation can be compared to casting a value from a higher rank to a lower and then back like in the following snippet:

unsigned int x = 257;
unsigned char y = x;
unsigned int x2 = y;
printf("%d\n", x==x2);   // 0

x = 255;
y = x;
x2 = y;
printf("%d\n", x==x2);   // 1

Upvotes: 0

dbush
dbush

Reputation: 225007

This line:

x=(float)3.3==3.3;

Compares (float)3.3 and 3.3 for equality and assigns the result to x. The left side of the comparison has type float because of the cast, while the right side has type double which is the default type for floating point constants.

The value 3.3 cannot be represented exactly in binary floating point, so the actual value stored is an approximation. This approximated value will be different for types float and double due to their differing precisions, so the equality will evaluated to false, i.e. 0. This is the value that gets assigned to x.

Regarding your comment on why x is 1 when the number you're checking is 3.5, that is because 3.5 can be represented exactly in binary, and both types have the precision to store that value, so they compare equal.

Upvotes: 5

stark
stark

Reputation: 13189

To see loss of precision with float:

#include <stdio.h>
int main(){
    float x = 3.3;
    double d = 3.3;
    printf("%12.9f %12.9lf\n",x, d);

Output:

 3.299999952  3.300000000

Upvotes: 1

Related Questions