当前位置: 动力学知识库 > 问答 > 编程问答 >

operators - Comparing float and double primitives in Java

问题描述:

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!

分享给朋友:
您可能感兴趣的文章:
随机阅读: