Java中的舍入误差
编写代码时,我们都会犯各种错误,这些错误会导致溢出错误和语法错误等问题。舍入误差是一种常见的错误,可能会导致给定数学问题的错误解决方案。通常,这种错误发生在我们使用浮点数时。
在本文中,我们将探讨此问题的原因,并尝试找到解决此类错误的方法。
舍入误差
浮点类型
它们也称为实数,在计算需要分数值时使用。它表示带有小数点的数字。例如,要表示1/5的结果,即0.2,正弦和余弦的结果也需要小数点。
在Java中,有两种类型的浮点数:
float − 它可以存储最大32位的单精度值。我们使用‘float’关键字声明它。
double − 其大小比float大,可以存储最大64位的双精度值。它使用‘double’关键字声明。
让我们讨论一个可能遇到舍入误差的例子,然后我们将了解原因,并提供适当处理它的解决方案。
示例1
public class Main{ public static void main(String[] args) { double data1 = 0.30; double data2 = 0.20 + 0.10; System.out.println("Value after addition: " + data2); System.out.println(data1 == data2); double data3 = 0.50; double data4 = 0.10 + 0.10 + 0.10 + 0.10 + 0.10; System.out.println("Value after addition: " + data4); System.out.println(data3 == data4); } }
输出
Value after addition: 0.30000000000000004 false Value after addition: 0.5 true
在上面的代码中,我们进行第一次加法运算时‘data2’的预期值是0.30,但在输出中我们得到了错误的结果。但是,当我们进行另一次类似的加法运算时,我们得到了准确的结果。
让我们来看另一个显示错误的例子。
示例2
public class Main { public static void main(String[] args) { double data1 = 4.30452; double data2 = 0.503542; double res = data1 + data2; System.out.println("Value after addition: " + res); } }
输出
Value after addition: 4.8080620000000005
预期输出是4.808062,但在这里我们得到了错误的输出。
错误原因
“IEEE 754”是Java在实现浮点数时遵循的标准。根据其“舍入”规则,当尾数的值大于23位时,它会将1加到第23位以舍入值。这里,尾数是分数数字的二进制表示。
这就是我们得到不同值的原因。
错误解决方案
为了避免这种舍入误差,我们有以下几种方法:
BigDecimal − 它是一个类,可以用作浮点数(如float和double)的替代。我们可以执行float和double数据类型提供的所有常规运算。例如,算术运算、比较和舍入。它可以以精确的精度处理这些运算。
以下示例演示了如何使用它来产生准确的结果。
示例3
import java.math.*; public class Main{ public static void main(String[] args) { BigDecimal data1 = new BigDecimal("0.20"); BigDecimal data2 = new BigDecimal("0.10"); BigDecimal res = data1.add(data2); // performing addition System.out.println("Value after addition: " + res); } }
输出
Value after addition: 0.30
在示例1中,我们在添加两个值时出错。在上面的示例中,我们使用了相同的值,但这次我们得到了正确的结果。
Math.round() − 它是‘Math’类的静态方法。它接受一个浮点值作为参数,并返回最接近的整数值。我们使用其类名调用它。
下面的示例说明了它在程序中的用法。
示例4
public class Main { public static void main(String[] args) { double data1 = 4.30452; double data2 = 0.503542; double res = data1 + data2; System.out.println("Value after addition: " + res); System.out.println("Value after rounding off the addition: " + Math.round(res)); } }
输出
Value after addition: 4.8080620000000005 Value after rounding off the addition: 5
结论
舍入误差不是编译时或运行时错误,Java编译器无法检测到它。这就是为什么程序员需要格外注意这些错误,否则我们将得到错误的结果。在本文中,我们讨论了原因,并提出了一些克服这种舍入误差的方法。