Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java模运算符的错误结果?_Java_Floating Point_Floating Accuracy_Modulo - Fatal编程技术网

Java模运算符的错误结果?

Java模运算符的错误结果?,java,floating-point,floating-accuracy,modulo,Java,Floating Point,Floating Accuracy,Modulo,我怀疑以前有人问过这个问题,但似乎找不到一个匹配的问题 我使用的是Scala,但我很确定这只是一个Java问题。。。输入值是双精度的 println(28.0 / 5.6) println(28.0 % 5.6) 这些行的结果是 5.0 1.7763568394002505E-15 这意味着Java正确地执行了除法,但由于某种原因,模数错误了,因为对于任何分解为整数的除法问题,模数都应该是0 有解决办法吗 谢谢 5.0只是表明Java所理解的精确结果更接近于5.0,而不是任何其他双精度

我怀疑以前有人问过这个问题,但似乎找不到一个匹配的问题

我使用的是Scala,但我很确定这只是一个Java问题。。。输入值是双精度的

println(28.0 / 5.6) 
println(28.0 % 5.6)
这些行的结果是

5.0 
1.7763568394002505E-15 
这意味着Java正确地执行了除法,但由于某种原因,模数错误了,因为对于任何分解为整数的除法问题,模数都应该是0

有解决办法吗


谢谢

5.0只是表明Java所理解的精确结果更接近于5.0,而不是任何其他双精度。这并不意味着手术的精确结果是5

现在,当你要求模数时,你可以降低到一个更精细的细节层次,因为结果并不局限于“5”部分

这不是一个很好的解释,但假设您有一个精度为4位的十进制浮点类型。1000/99.99和1000%99.99的结果是什么

好的,真正的结果从10.001001开始-所以你必须把它四舍五入到10.00。但是,余数是0.10,可以表示为0.10。同样,看起来除法给了你一个整数,但它不完全一样

记住这一点,请记住,5.6的字面值实际上是5.5999999996447286321199499070644378662109375。现在很明显,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
    }
}
算术 首先,十进制数5.6不能用二进制浮点精确表示。将其四舍五入为精确的二进制分数3152519739159347/249

28.0/5.6=5.0是因为5.0是最接近真实结果的
double
数字,其中真实结果为5.000000000000000 3172065784643

对于28.0%5.6,真实结果正好是1/249,约为1.776×10−15,因此计算是正确的四舍五入

权变措施 你为什么需要一个变通办法?对于大多数应用程序,保留稍微错误的结果是可以的。您是否担心显示“漂亮”的结果

如果您需要绝对精确的算法,那么您将需要使用BigFraction的一些实现

进一步阅读 各种文章都介绍了浮点警告的主题:


(按读者友好度的降序排列。)

结果实际上不是0,但非常接近(0.00000000000000 177635…)。问题是有些十进制数不能用二进制精确表示,所以这就是问题的所在;我怀疑同样的结果会在C/C++中打印出来。

这是我使用模运算符检查双精度值是否可被另一个值整除的解决方案:

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));
    }
}
公共类双重操作
{
公共静态最终双ε=0.000001d;
公共静态布尔等于(双值1,双值2)
{
返回(数学绝对值(val1-val2)
您正在进行浮点运算。除法不会给你“5”,但会给你“5.0”。没有无限的精确性。模给你余数,这也是同样的精度问题,给你一些接近0的东西。在你的精度范围内,这与答案相当接近。唯一的解决办法是:不要做浮点运算,你的目标是得到精确的答案吗?FWIW:C#会产生与double相同的结果,所以这显然不仅仅是Java的问题。@StriplingWarrior:这根本不是Java或C#的“问题”。这是OP对结果的解释问题:)@Sam:你不是在处理十进制数学系统,你也不是在处理56-你是在处理“最接近5.6的双精度”,这确实是非常不同的。如果你一直试图坚持你对浮点运算在世界其他地方的工作方式的看法,你会失望的。学习二进制浮点实际上是如何工作的,应该避免什么,以及替代方法是什么,对您来说会更有成效。(例如,Java中的BigDecimal。)@Sam:但是
double
根本不是十进制的数学系统。这是一个二进制数学系统。一旦你知道了这一点,剩下的就很容易了。如果使用正确的类型,在Java中也不需要考虑这一点,但我确实认为,期望软件工程师了解他们使用的语言中类型的基本原理(不是细节,而是基本原理)是合理的。理解
double
不是十进制浮点类型(与C#中的
decimal
不同)至关重要。对我来说,这就像知道一个
字符串
是由字符组成的,而不是由字节组成的,这很重要。更准确地说,它比println的默认浮点精度表示的任何其他双精度都接近5.0。@Nayuki:No,5.0“与任何其他双精度一样接近操作的理论结果”。我并没有说5.0不完全是5-我说精确的结果不是5。看到我编辑的答案的下半部分,你就会明白我的意思了…@Nayuki Minase:在计算本身中,有一点浮点不精确,但是当你将计算值表示为一个带整数的双精度值时,它就失去了保持这种不精确性所需的精度(奇怪吧?)。double没有足够的位来表示5.000000000000001,因此它将精确地变成5.0。但是,当计算结果不再包括“5”时,将导致0.00000000