浮点变量不起作用

时间:2014-02-23 00:51:03

标签: java

当我运行下面发布的程序时,我得到了一些奇怪的结果。

该程序假设以i = 5,000,000的倍数打印消息,但是,当i不等于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

2 个答案:

答案 0 :(得分:6)

这是因为名为numeric promotion的事情。任何时候有一个涉及两种不同类型数字的表达式,“最窄”的数字将被提升为“最宽”的数字。

你有一个这样的表达式:

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

这里,IncrementPercentageToPrintResults是一个浮点数,因此表达式中的每个其他数字都会被提升为浮点数。

问题在于,对于大数字,float实际上不如int精确。

实际上,对于浮点数,在±2 ^ 24(±16,777,216)之后,它不能再代表奇数。所以像19,999,999这样的数字会变为20,000,000。数字越大,浮点变得越不精确。

有许多解决方案,这里最好的解决方案是不要将int乘以浮点分数来进行除法。只需将numberOfTests除以10:

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

另一个OK解决方案是使用double而不是float,因为double可以完全表示int中的所有值。

另一个是,如果你真的想要,将生成的float转换为int:

(int)(IncrementsPercentageToPrintResults * numberOfTests)

但是,乘法表达式仍然四舍五入为浮点数,因此只能在此处起作用,因为float可以精确地表示值5,000,000。有时像这样的演员是必要的,但在这里不是。只需使用除法或加倍。

两个强制性链接是:

答案 1 :(得分:2)

问题出在以下几行:

i % (IncrementsPercentageToPrintResults * numberOfTests)

(IncrementsPercentageToPrintResults * numberOfTests)会产生浮点值,因为IncrementsPercentageToPrintResults会将其强制转换为浮点值。浮点值不应与模数运算符一起使用,因为计算机处理浮点值的方式。快速修复如下:

i % (int) (IncrementsPercentageToPrintResults * numberOfTests)

这会将结果转换为修正此问题的整数。