注意:问题仍未得到彻底解答!这个问题不涉及浮点部分的截断问题!!!
在Java中,我有这个简单的代码:
double sum = 0.0;
for(int i = 1; i <= n; i++){
sum += 1.0/n
}
System.out.println("Sum should be: 1");
System.out.println("The result is: " + sum);
其中n可以是任何整数。对于像7,9这样的数字,和的期望值是和的最后一位数字有差,结果是0。999999999998什么的,但是当我使用3时,输出是1.0
。
如果你把1/3加3次,你会得到一个接近1的数字,但是我得到的正好是1.0。
为什么?
这是因为除法是以整数进行的。
1/n
总是为n给出0
因此,你总是得到sum = 0 1/1 0 0...
尝试使用 1.0 / n
如果你把1/3加3次,你会得到一个接近1的数字,但是我得到的正好是1.0。
实际上,一个没有编程经验的正常人会期望n*1/n等于1,但我们在这里并不正常。
我不能完全重现你的问题,我明白
groovy:000> def foo(n) {
groovy:001> sum = 0.0
groovy:002> for (int i = 0; i < n; i++) {
groovy:003> sum += 1.0 / n
groovy:004> }
groovy:005> sum
groovy:006> }
===> true
groovy:000> foo(3)
===> 0.9999999999
这里可能有两个问题,至少你会想知道它们。
一个是双精度不精确,它们不能准确地表示某些值,你只需要期望东西偏离一点点。你的目标不是100%的准确性,而是将误差保持在可接受的范围内。(彼得·劳里(Peter Lawrey)有一篇关于双打的有趣文章,你可能想看看。如果这对你来说不行,你会想避免双打。对于很多用途,BigDecimal 已经足够好了。如果你想要一个库中的问题,你的问题中的除法问题给出了准确的答案,你可以查看这个问题的答案。
另一个问题是System.out.println没有告诉你双精度的确切值,它有点捏造。如果添加如下行:
System.out.println(new java.math.BigDecimal(sum));
然后你就会准确地看到这个替身包含了什么。
我不确定这是否有助于澄清事情,因为我不确定你认为是什么问题。
这是一个使用BigDecimal的测试程序,如前所述,显示中间答案的值。在最后一步,将1.0/3的第三个副本添加到两个副本的总和中,确切的答案在1.0和比它低一倍的下一个副本之间。在这种情况下,四舍五入规则选择1.0。
鉴于此,我认为它应该四舍五入到1.0,与问题标题相矛盾。
测试程序:
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
final double oneThirdD = 1.0/3;
final BigDecimal oneThirdBD = new BigDecimal(oneThirdD);
final double twoThirdsD = oneThirdD + oneThirdD;
final BigDecimal twoThirdsBD = new BigDecimal(twoThirdsD);
final BigDecimal exact = twoThirdsBD.add(oneThirdBD);
final double nextLowerD = Math.nextAfter(1.0, 0);
final BigDecimal nextLowerBD = new BigDecimal(nextLowerD);
System.out.println("1.0/3: "+oneThirdBD);
System.out.println("1.0/3+1.0/3: "+twoThirdsBD);
System.out.println("Exact sum: "+exact);
System.out.println("Rounding error rounding up to 1.0: "+BigDecimal.ONE.subtract(exact));
System.out.println("Largest double that is less than 1.0: "+nextLowerBD);
System.out.println("Rounding error rounding down to next lower double: "+exact.subtract(nextLowerBD));
}
}
输出:
1.0/3: 0.333333333333333314829616256247390992939472198486328125
1.0/3+1.0/3: 0.66666666666666662965923251249478198587894439697265625
Exact sum: 0.999999999999999944488848768742172978818416595458984375
Rounding error rounding up to 1.0: 5.5511151231257827021181583404541015625E-17
Largest double that is less than 1.0: 0.99999999999999988897769753748434595763683319091796875
Rounding error rounding down to next lower double: 5.5511151231257827021181583404541015625E-17