问题描述:

I came across a strange corner of Java.(It seems strange to me)

`double dd = 3.5;`

float ff = 3.5f;

System.out.println(dd==ff);

**o/p: true**

`double dd = 3.2;`

float ff = 3.2f;

System.out.println(dd==ff);

**o/p: false**

I observed that if we compare any two values (a float and a double as I mentioned in the example) with `.5`

OR `.0`

like 3.5, 234.5, 645.0

then output is `true`

i.e. two values are equal otherwise output is `false`

though they are equals.

Even I tried to make method `strictfp`

but no luck.

Am I missing out on something.

Take a look at What every computer scientist should know about floating point numbers.

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation....

--- Edit to show what the above quote means ---

You shouldn't ever compare floats or doubles for equality; because, you can't really guarantee that the number you assign to the float or double is exact.

So

```
float x = 3.2f;
```

doesn't result in a float with a value of 3.2. It results in a float with a value of 3.2 plus or minus some very small error. Say 3.19999999997f. Now it should be obvious why the comparison won't work.

To compare floats for equality sanely, you need to check if the value is "close enough" to the same value, like so

```
float error = 0.000001 * second;
if ((first >= second - error) || (first <= second + error)) {
// close enough that we'll consider the two equal
...
}
```

The difference is that 3.5 can be represented *exactly* in both `float`

and `double`

- whereas 3.2 can't be represented exactly in either type... and the two closest approximations are different.

Imagine we had two fixed-precision *decimal* types, one of which stored 4 significant digits and one of which stored 8 significant digits, and we asked each of them to store the number closest to "a third" (however we might do that). Then one would have the value 0.3333 and one would have the value 0.33333333.

An equality comparison between `float`

and `double`

first converts the `float`

to a `double`

and then compares the two - which would be equivalent to converting 0.3333 in our "small decimal" type to 0.33330000. It would then compare 0.33330000 and 0.33333333 for equality, and give a result of false.

The common implementation of floating point numbers, IEEE754, allows for the precise representation of only those numbers which have a *short, finite binary expansion*, i.e. which are a sum of finitely many (nearby) powers of two. All other numbers cannot be precisely represented.

Since `float`

and `double`

have different sizes, the representation in both types for a non-representable value are different, and thus they compare as unequal.

(The *length* of the binary string is the size of the mantissa, so that's 24 for `float`

, 53 for `double`

and 64 for the 80-bit extended-precision float (not in Java). The *scale* is determined by the exponent.)

floating point is a binary format and it can represent numbers as a sum of powers of 2. e.g. 3.5 is 2 + 1 + 1/2.

float 3.2f as an approximation of 3.2 is

```
2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/4194304 + a small error
```

However double 3.2d as an approximation of 3.2 is

```
2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/8388608+ 1/16777216+ 1/134217728+ 1/268435456+ 1/2147483648+ 1/4294967296+ 1/34359738368+ 1/68719476736+ 1/549755813888+ 1/1099511627776+ 1/8796093022208+ 1/17592186044416+ 1/140737488355328+ 1/281474976710656+ 1/1125899906842624 + a smaller error
```

When you use floating point, you need to use appropriate rounding. If you use BigDecimal instead (and many people do) it has rounding built in.

```
double dd = 3.2;
float ff = 3.2f;
// compare the difference with the accuracy of float.
System.out.println(Math.abs(dd - ff) < 1e-7 * Math.abs(ff));
```

BTW the code I used to print the fractions for double.

```
double f = 3.2d;
double f2 = f - 3;
System.out.print("2+ 1");
for (long i = 2; i < 1L << 54; i <<= 1) {
f2 *= 2;
if (f2 >= 1) {
System.out.print("+ 1/" + i);
f2 -= 1;
}
}
System.out.println();
```

This should work:

```
BigDecimal ddBD = new BigDecimal(""+dd);
BigDecimal ffBD = new BigDecimal(""+ff);
// test for equality
ddBO.equals(ffBD);
```

Always work with **BigDecimal** when you want to compare floats or doubles
and always use the BigDecimal constructor with the **String parameter**!