我怀疑之前已经问过,但似乎找不到匹配的问题......
我正在使用Scala,但我很确定这只是一个Java问题......输入值是双倍的
println(28.0 / 5.6)
println(28.0 % 5.6)
这些行的结果是
5.0
1.7763568394002505E-15
这意味着Java正确执行除法,但由于某种原因导致模数错误,因为对于任何解析为整数的除法问题,模数应为0 ...
有解决方法吗?
谢谢!
答案 0 :(得分:12)
5.0只显示了精确结果,因为Java了解它比任何其他双精度更接近5.0。这并不意味着操作的确切结果完全 5。
现在,当你要求模数时,你可以降低到更精细的细节水平,因为结果不是固定为“5”部分。
这不是一个很好的解释,但想象你有一个4位精度的十进制浮点类型。什么是1000 / 99.99和1000%99.99的结果?
嗯,实际结果从10.001001开始 - 所以你必须将其舍入到10.00。但是,余数是0.10,您可以表达。所以再一次,看起来就像分区给你一个整数,但它不是相当。
考虑到这一点,请记住您的5.6字面值实际上 5.5999999999999996447286321199499070644378662109375。现在显然28.0(其中*可以)被精确地除以该数字并不完全是5。
编辑:现在,如果使用BigDecimal
使用十进制浮点运算执行结果,则的值正好是5.6,并且没有问题:
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
BigDecimal x = new BigDecimal("28.0");
BigDecimal y = new BigDecimal("5.6");
BigDecimal div = x.divide(y);
BigDecimal rem = x.remainder(y);
System.out.println(div); // Prints 5
System.out.println(rem); // Prints 0.0
}
}
答案 1 :(得分:2)
首先,十进制数5.6不能用二进制浮点精确表示。它四舍五入到精确的二进制分数3152519739159347/2 49 。
28.0 / 5.6 = 5.0的事实是因为5.0是与真实结果最接近的double
数字,其中真实结果为5.0000000000000003172065784643 ....
对于28.0%5.6,真实结果恰好是1/2 49 ,大约是1.776×10 -15 ,因此计算正确舍入。 / p>
为什么需要解决方法?对于大多数应用程序,保持稍微错误的结果是好的。您是否担心显示“漂亮”的结果?
如果您需要绝对精确的算术,那么您将需要使用BigFraction的一些实现。
浮点警告的主题已在各种文章中介绍过:
(以读者友好的顺序递减。)
答案 2 :(得分:2)
结果实际上不是0,但它非常接近(0.00000000000000177635 ......)。问题是一些十进制数字不能用二进制表示,所以这就是问题的来源;我怀疑在C / C ++中会打印出相同的结果。
答案 3 :(得分:0)
这是我的解决方案,用于检查双值是否可以被另一个使用模运算符整除:
public class DoubleOperation
{
public static final double EPSILON = 0.000001d;
public static boolean equals(double val1, double val2)
{
return (Math.abs(val1 - val2) < EPSILON);
}
public static boolean divisible(double dividend, double divisor)
{
double divisionRemainder = dividend % divisor;
return (equals(divisionRemainder, 0.0d) || equals(divisionRemainder, divisor));
}
}