4

我有以下代码行。

hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()));
  • void onBeingHit(int decHP)方法接受整数并更新健康点。
  • float getDefensePercent()方法是返回英雄防御百分比的getter方法。
  • ENEMY_ATTACK_POINT是一个宏常数因子,定义为#define ENEMY_ATTACK_POINT 20

假设hero->getDefensePercent()返回0.1。所以计算是

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

每当我尝试使用以下代码时(不f附加1.0

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

我得到了17

但是对于以下代码(f附加在之后1.0

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

我得到了18

这是怎么回事?f尽管hero->getDefensePercent()已经处于浮动状态,但是否具有重要意义?

4

3 回答 3

11

这是怎么回事?为什么在这两种情况下都不是整数结果18

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

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

好的,但是既然两者都double表现float得像那样,为什么我会18陷入这两种情况中的一种,而17在另一种情况下呢?我很困惑。

您的代码获取函数的结果0.1f(浮点数),然后计算20 * (1.0 - 0.1f)哪个是双精度表达式,而哪个是20 * (1.0f - 0.1f)浮点表达式。现在 float 版本恰好略大于18.0并向下舍入为18,而 double 表达式略小于18.0并向下舍入为17

如果您不确切知道 IEEE754 二进制浮点数是如何从十进制数构造的,那么如果它略小于或略大于您在代码中输入的十进制数,那么它几乎是随机的。所以你不应该指望这个。不要试图通过附加f到其中一个数字并说“现在它可以工作,所以我把它f留在那里”来解决这样的问题,因为另一个值的行为再次不同。

为什么表达式的类型取决于 this 的出现f

这是因为 C 和 C++ 中的浮点字面量是double默认类型的。如果添加f,它是一个浮点数。浮点表达式的结果属于“更大”类型。双精度表达式和整数的结果仍然是双精度表达式,而 int 和浮点数将是浮点数。所以你的表达式的结果是浮点数或双精度数。

好的,但我不想四舍五入为零。我想四舍五入到最接近的数字。

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

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

在 C++11 中,有std::round()这样的功能。在标准的早期版本中,没有这样的函数来四舍五入到最接近的整数。(详情请看评论。)

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

int round(double x) {
    return (x < 0.0) ? (x - .5) : (x + .5);
}
于 2013-02-15T08:00:17.937 回答
4

1.0 被解释为双精度,而 1.0f 被编译器视为浮点数。

f 后缀只是告诉编译器哪个是浮点数,哪个是双精度数。

顾名思义,双精度数是浮点数的 2 倍。通常,双精度具有 15 到 16 位十进制数字,而浮点只有 7。

这种精度损失可能导致截断错误更容易上浮

请参阅 MSDN (C++)

于 2013-02-15T07:55:38.590 回答
4

发生这种情况的原因是使用时更精确的结果double,即1.0

尝试四舍五入你的结果,这将导致转换后更精确的积分结果:

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

请注意,在它之后添加0.5和截断int会导致结果四舍五入,因此当您的结果为17.999...时,它将变为18.499...,这将被截断为18

于 2013-02-15T08:00:03.980 回答