浮点计算给出与浮点数不同的结果 [英] Floating point calculation gives different results with float than with double

查看:142
本文介绍了浮点计算给出与浮点数不同的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码行。

hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()));




  • void onBeingHit(int decHP) code>方法接受整数并更新健康点。

  • float getDefensePercent()方法是一个返回防御的getter方法一个英雄的百分比。

  • ENEMY_ATTACK_POINT 是一个定义为的宏常数因子#define ENEMY_ATTACK_POINT 20

    • void onBeingHit(int decHP) method accepts integer number and updates health points.
    • float getDefensePercent() method is a getter method returning the defense percent of a hero.
    • ENEMY_ATTACK_POINT is a macro constant factor defined as #define ENEMY_ATTACK_POINT 20.
    • 让我们说 hero-> getDefensePercent()返回 0.1 。所以计算是

      Let's say hero->getDefensePercent() returns 0.1. So the calculation is

      20 * (1.0 - 0.1)  =  20 * (0.9)  =  18
      

      每当我尝试使用以下代码(no f 追加 1.0

      Whenever I tried it with the following code (no f appending 1.0)

      hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()));
      

      我有 17

      但是对于 1.0 之后的以下代码( f

      But for the following code (f appended after 1.0)

      hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0f - hero->getDefensePercent()));
      

      我有 18

      发生了什么事? f 中有显着的效果,而英雄 - > getDefensePercent()已经在浮动?

      What's going on? Is f significant to have at all although hero->getDefensePercent() is already in float?

      推荐答案

      发生了什么?为什么在这两种情况下整数结果 18

      What's going on? Why isn't the integer result 18 in both cases?

      问题是结果在转换为整数值(在这两种情况下)的浮点数表达式都将向零舍入。

      The problem is that the result of the floating point expression is rounded towards zero when being converted to an integer value (in both cases).

      0.1 不能被正确地表示为浮点值(在这两种情况下)。编译器将转换为二进制IEEE754浮点数,并决定是向上还是向下舍入为可表示值。然后,处理器在运行时将这个值进行乘法运算,并将结果四舍五入以获得一个整数值。

      0.1 can't be represented exactly as a floating point value (in both cases). The compiler does the conversion to a binary IEEE754 floating point number and decides whether to round up or down to a representable value. The processor then multiplies this value during runtime and the result is rounded to get an integer value.

      好的,但既然 double float 这样做,为什么在两种情况之一中得到 18 但另一种情况下 17 我感到困惑。

      Ok, but since both double and float behave like that, why do I get 18 in one of the two cases, but 17 in the other case? I'm confused.

      您的代码需要该函数的结果, 0.1f (a float),然后计算 20 *(1.0 - 0.1f),这是一个双重表达式,而 20 *(1.0f - 0.1f)是一个浮点型表达式。现在,浮动版本恰好比 18.0 略大,并且被四舍五入为 18 ,而双重表达式略微少于 18.0 ,并被舍入到 17

      Your code takes the result of the function, 0.1f (a float), and then calculates 20 * (1.0 - 0.1f) which is a double expression, while 20 * (1.0f - 0.1f) is a float expression. Now the float version happens to be slightly larger than 18.0 and gets rounded down to 18, while the double expression is slightly less than 18.0 and gets rounded down to 17.

      如果您不知道如何从十进制数构建IEEE754二进制浮点数,那么如果它稍微小于或略大于您在代码中输入的十进制数,那么它是非常随机的。所以你不要指望这个。不要尝试通过将 f 附加到其中一个数字来解决这个问题,并说现在它可以工作,所以我离开这个 f there,因为另一个值的行为不同。

      If you don't know exactly how IEEE754 binary floating point numbers are constructed from decimal numbers, it's pretty much random if it will be slightly less or slightly greater than the decimal number you've entered in your code. So you shouldn't count on this. Don't try to fix such an issue by appending f to one of the numbers and say "now it works, so I leave this f there", because another value behaves differently again.

      为什么要根据这个 f

      Why depends the type of the expression on the precence of this f?

      这是因为C和C ++中的浮点文字类型为 double 每个默认值。如果添加 f ,它是一个浮点数。浮点表达的结果是较大类型。 double表达式和整数的结果仍然是double表达式,int和float将是一个float。所以你的表达式的结果是一个浮点数或一个double。

      This is because a floating point literal in C and C++ is of type double per default. If you add the f, it's a float. The result of a floating point epxression is of the "greater" type. The result of a double expression and an integer is still a double expression as well as int and float will be a float. So the result of your expression is either a float or a double.

      好的,但我不想回合到零。我想要舍入到最接近的数字。

      Ok, but I don't want to round to zero. I want to round to the nearest number.

      要解决此问题,请在转换为整数之前,将一半添加到结果中:

      To fix this issue, add one half to the result before converting it to an integer:

      hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()) + 0.5);
      

      在C ++ 11中有 std :: round() 。在以前的标准版本中,没有这样的功能可以舍入到最接近的整数。(请参阅有关详细信息。)

      In C++11, there is std::round() for that. In previous versions of the standard, there was no such function to round to the nearest integer. (Please see comments for details.)

      如果您没有 std :: round ,您可以自己写处理负数时要小心。当转换为整数时,数字将被截断(向零舍入),这意味着负值将被舍入,而不是向下舍入。因此,如果数字为负,我们必须将减去一半:

      If you don't have std::round, you can write it yourself. Take care when dealing with negative numbers. When converting to an integer, the number will be truncated (rounded towards zero), which means that negative values will be rounded up, not down. So we have to subtract one half if the number is negative:

      int round(double x) {
          return (x < 0.0) ? (x - .5) : (x + .5);
      }
      

      这篇关于浮点计算给出与浮点数不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆