2014-02-23 67 views
3

当我运行下面发布的程序时,我得到了一些奇怪的结果。浮点变量不工作

该程序假设打印消息的倍数为i = 5,000,000,但是,当我不等于500万的倍数时,它有时会打印消息。

当我将numberOfTests从5000万更改为500万时,程序运行良好。另外,如果我将它从float更改为double,则该程序也可以正常工作。

我现在的代码有什么问题?浮动变量不工作?这是为什么发生?我今后如何防止这种情况发生?

public static void main(String[] args) 
{ 
    final int numberOfTests = 50 * 1000 * 1000; 
    final float IncrementsPercentageToPrintResults = .10f; 

    for(int i = 1; i <= numberOfTests; i++) 
    { 
     if(i % (IncrementsPercentageToPrintResults * numberOfTests) == 0) 
     { 
      System.out.println("Currently at " + (int) (((float) i/numberOfTests) * 100) + "%."); 
      System.out.println(" i = " + i);     
     } 
    } 

} 

Output: 
Currently at 10%. 
i = 5000000 
Currently at 20%. 
i = 10000000 
Currently at 30%. 
i = 15000000 
Currently at 40%. 
i = 19999999 
Currently at 40%. 
i = 20000000 
Currently at 40%. 
i = 20000001 
Currently at 50%. 
i = 24999999 
Currently at 50%. 
i = 25000000 
Currently at 50%. 
i = 25000001 
Currently at 60%. 
i = 29999999 
Currently at 60%. 
i = 30000000 
Currently at 60%. 
i = 30000001 
Currently at 70%. 
i = 34999998 
Currently at 70%. 
i = 34999999 
Currently at 70%. 
i = 35000000 
Currently at 70%. 
i = 35000001 
Currently at 70%. 
i = 35000002 
Currently at 80%. 
i = 39999998 
Currently at 80%. 
i = 39999999 
Currently at 80%. 
i = 40000000 
Currently at 80%. 
i = 40000001 
Currently at 80%. 
i = 40000002 
Currently at 90%. 
i = 44999998 
Currently at 90%. 
i = 44999999 
Currently at 90%. 
i = 45000000 
Currently at 90%. 
i = 45000001 
Currently at 90%. 
i = 45000002 
Currently at 100%. 
i = 49999998 
Currently at 100%. 
i = 49999999 
Currently at 100%. 
i = 50000000 
+1

我认为[这个链接](http://www.youtube.com/watch?v=PZRI1IfStY0&list= UU9-y-6csu5WGm29I7JiwpnA&feature = share&index = 7)将揭示这个问题。 – Makoto

+0

这有助于很多!谢谢 – Programmer

+0

可能重复的[是浮点数学破碎?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) –

回答

6

这是因为叫做numeric promotion。任何时候都有涉及两种不同类型数字的表达式,“最窄”数字会被提升为“最宽”数字。

你有一个表达这样的位置:

if(i % (IncrementsPercentageToPrintResults * numberOfTests) == 0) 

这里,IncrementPercentageToPrintResults是float所以它发生在表达每隔数提升为浮动。

问题是,对于大数字,float实际上比int小。

所以实际上,对于一个float,在2^24(±16,777,216)之后,它不能再表示奇数。所以像19,999,999这样的数字四舍五入到20,000,000。数字越大,浮点越不精确。

有很多解决方案,这里最好的方法就是不用一个浮点数乘以一个int来完成除法。只是划分numberOfTests 10:

if(i % (IncrementsPercentageToPrintResults/10) == 0) 

其他OK的解决方案是双改用浮动的,因为双可以在一个int代表所有值完全相同。

另一个原因是,如果你真的想,所得到的浮动转换为int:

(int)(IncrementsPercentageToPrintResults * numberOfTests) 

然而,乘法表达式仍然四舍五入浮动,使得只有在这里工作,因为浮动可以代表价值500万究竟。有时候这样的演员是必要的,但这不是。只需使用除法或双精度。

两个强制性链接:

2

问题是与下面的行:

i % (IncrementsPercentageToPrintResults * numberOfTests) 

(IncrementsPercentageToPrintResults * numberOfTests)是浮动因为IncrementsPercentageToPrintResults的类型,它不应该与模运算符可以使用的。快速解决方案如下:

i % (int)(IncrementsPercentageToPrintResults * numberOfTests) 

这会将结果强制转换为解决此问题的整数。