简体   繁体   English

浮点变量不起作用

[英]Floating Point Variable Not Working

When I run the program posted below, I get some weird results. 当我运行下面发布的程序时,我得到了一些奇怪的结果。

The program is suppose to print a message at multiples of when i = 5,000,000, however, it sometimes prints the message when i is not equal to a multiple of 5 million. 该程序假设以i = 5,000,000的倍数打印消息,但是,当i不等于500万的倍数时,它有时会打印消息。

When I change the numberOfTests from 50 million to 5 million, the program runs fine. 当我将numberOfTests从5000万更改为500万时,程序运行正常。 Also, if I change it from a float to a double, the program works fine as well. 此外,如果我将它从float更改为double,程序也可以正常工作。

What's wrong with my current code? 我目前的代码出了什么问题? Is the floating variable not working? 浮动变量不起作用吗? Why is this happening? 为什么会这样? How can I prevent this in the future? 我怎么能在将来防止这种情况发生?

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

This happens because of something called numeric promotion . 这是因为称为数字促销的事情。 Any time there is an expression involving two different types of numbers, the "narrowest" numbers are promoted to the "widest" numbers. 任何时候有一个表达涉及两种不同类型的数字,“最窄”的数字被提升为“最宽”的数字。

You have an expression like this here: 你有一个这样的表达式:

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

Here, IncrementPercentageToPrintResults is a float so it happens that every other number in the expression gets promoted to float. 这里, IncrementPercentageToPrintResults是一个浮点数,因此表达式中的每个其他数字都会被提升为浮点数。

The problem is that for large numbers, float is actually less precise than an int. 问题是,对于大数字,float实际上不如int精确。

So actually, for a float, after ±2^24 (±16,777,216), it cannot represent odd numbers anymore. 实际上,对于浮点数,在±2 ^ 24(±16,777,216)之后,它不能再代表奇数。 So a number like 19,999,999 gets rounded to 20,000,000. 所以像19,999,999这样的数字会变为20,000,000。 The larger the number is, the more imprecise floating point becomes. 数字越大,浮点变得越不精确。

There are a number of solutions and the best one here is to simply not multiply an int by a floating point fraction to do division. 有许多解决方案,这里最好的解决方案是不要将int乘以浮点分数来进行除法。 Just divide numberOfTests by 10: 只需将numberOfTests除以10:

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

The other OK solution is to use double instead of float because double can represent all values in an int exactly. 另一个OK解决方案是使用double而不是float,因为double可以精确地表示int中的所有值。

Another is, if you really want, to cast the resulting float to an int: 另一个是,如果你真的想要,将生成的float转换为int:

(int)(IncrementsPercentageToPrintResults * numberOfTests)

However, the multiplication expression is still rounded to float so that only works here because float can represent the value 5,000,000 exactly. 但是,乘法表达式仍然舍入为浮点数,因此只能在此处起作用,因为float可以精确地表示值5,000,000。 Sometimes a cast like that is necessary but here it's not. 有时像这样的演员是必要的,但在这里不是。 Just use division or double. 只需使用除法或双倍。

The two obligatory links are: 这两个强制性链接是:

The problem is with the following line: 问题出在以下几行:

i % (IncrementsPercentageToPrintResults * numberOfTests)

(IncrementsPercentageToPrintResults * numberOfTests) results in a float value because IncrementsPercentageToPrintResults will typecast it to a float. (IncrementsPercentageToPrintResults * numberOfTests)会产生浮点值,因为IncrementsPercentageToPrintResults会将其类型转换为浮点数。 Float values shouldn't be used with the modulus operator because of how computers handle float values. 浮点值不应与模数运算符一起使用,因为计算机处理浮点值的方式。 A quick fix would be the following: 快速解决方案如下:

i % (int) (IncrementsPercentageToPrintResults * numberOfTests)

That'll cast the result to be an integer which fixes this issue. 这会将结果转换为修正此问题的整数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM