Java: Float comparison


foreword

The comparison of Java floating-point numbers is a problem often encountered in development, but it is easy to make mistakes.

This article mainly introduces the correct method and common precautions for floating-point number comparison.


1. Reasons for errors in comparison of floating-point numbers

To put it simply: When comparing floating-point numbers, the precision will be lost, and the comparison result may be wrong.

Because the comparison of floating-point numbers involves type promotion, and binary cannot store the exact values ​​of some numbers (such as 3.1415926...), so some values ​​will be rounded when storing, which will cause errors.

At the same time, the precision of float and double is not the same, so errors will also occur.

For details, please refer to this article: Floating point comparison in Java == equals and compare

Second, the correct way to compare floating point numbers

1. Set the margin of error

Principle analysis: When the difference between two floating-point numbers is less than a certain limit value, we consider the two numbers to be equal.

Note: This limit value can be set according to the specific requirements of the system and the environment, generally it is 10 to the -7th power or 10 to the -14th power.

The sample code is as follows:

final double limitValue = .000001;
double d1 = .1 * 3;
double d2 = .3;
if(Math.abs(d1-d2) < limitValue) {
    
    
	System.out.println("d1 和 d2 相等");
} else {
    
    
	System.out.println("d1 和 d2 不相等");
}

2. Use BigDemical

Friends who are not familiar with this class can learn about it first: Detailed explanation of BigDecimal in java

Note: When BigDemical constructs a number, be sure to pass in a string instead of a number:

BigDecimal num=new BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。//推荐使用

The reason is: when the incoming number is a decimal, it is an imprecise value, and the exact operation stored in BigDecimal, using the exact type to store the imprecise number is prone to problems.

BigDecimal num=new BigDecimal(0.1d) //不推荐使用

The sample code is as follows:

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
BigDecimal x = a.subtract(b);
BigDecimal y = b.subtract(c);
if (x.equals(y)) {
    
    
    System.out.println("true");
}

For more information, please refer to : How should floating-point numbers in Java be compared to be the optimal solution? Do you really know what it is, and why?


3. Expansion: Java's 0.0 and -0.0 traps

Unfamiliar friends may be surprised to see this title: Isn't 0.0 and -0.0 the same? Why is it a trap?

The reason is: In Java, double distinguishes + 0.0 and - 0.0, that is to say, +0.0 and -0.0 are two different numbers, and +0.0 is greater than -0.0.
Because one bit is a sign bit during specific storage, +0.0 and -0.0 are not the same when stored internally, but the values ​​are the same

You can refer to:
java floating point number, -0.0 is less than +0.0
Why do we have 0.0 and -0.0 in Ruby?
The correct way to compare floating point types in Java

Code example:

System.out.println(0.0 == -0.0);
System.out.println(Double.compare(0.0, -0.0));
System.out.println(new Double(0.0).equals(new Double(-0.0)));
Map<Double, Integer> map = new HashMap<>();
map.put(0.0, 1);
map.put(-0.0, 2);
System.out.println(map.size());
System.out.println((double)(2-2)/(1-2));
System.out.println((double)(3-3)/(2-1));

Output result:

true
1
false
2
-0.0
0.0

Therefore, when using HashSet to store, if the key is a floating point number, then it must be noted that 0.0 and -0.0 can be used as two keys to interpolate to the HashSet.

The solution is: set.add(num+0.0) , which will not affect the specific value, and can also overcome the 0.0 and -0.0 problems.

Trap sharing: [Treading the pit] Java double distinguishes positive 0 and negative 0

Summarize

This article mainly introduces the reasons why there are errors in the comparison of floating-point numbers in Java, and introduces the correct method for comparison of floating-point numbers.

The error-prone points are:
(1) When BigDemical constructs numbers, be sure to pass in strings instead of numbers
(2) 0.0 and -0.0 problems

hope its good for U.S!

Guess you like

Origin blog.csdn.net/qq_46119575/article/details/129521129