浮点计算给出的结果与使用双精度计算的结果不同
Floating point calculation gives different results with float than with double
我有以下代码行。
hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()));
-
void onBeingHit(int decHP)
方法接受整数并更新运行状况点。 -
float getDefensePercent()
方法是一种获取方法,返回英雄的防御百分比。 -
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。
这是怎么回事?尽管hero->getDefensePercent()
已经处于浮动状态,但f
重要吗?
这是怎么回事?为什么在这两种情况下整数结果都不18
?
问题是浮点表达式的结果在转换为整数值时四舍五入为零(在这两种情况下(。
0.1
不能完全表示为浮点值(在这两种情况下(。编译器将转换为二进制IEEE754浮点数,并决定是向上舍入还是向下舍入为可表示的值。然后,处理器在运行时将此值相乘,结果将四舍五入以获得整数值。
好的,但是既然double
和float
的行为都是这样的,为什么我在两种情况下18
,而在另一种情况下17
?我很困惑。
代码获取函数的结果,0.1f
(浮点数(,然后计算20 * (1.0 - 0.1f)
哪个是双精度表达式,而20 * (1.0f - 0.1f)
是浮点表达式。现在浮点数版本恰好比18.0
略大,四舍五入到18
,而双精度表达式略小于18.0
,四舍五入到17
。
如果您不知道二进制浮点数是如何从十进制数构造IEEE754那么如果它略小于或略大于您在代码中输入的十进制数,则几乎是随机的。所以你不应该指望这个。不要试图通过将f
附加到其中一个数字并说"现在它可以工作,所以我把这个f
留在那里"来解决这个问题,因为另一个值的行为再次不同。
为什么表达式的类型取决于此f
的优先级?
这是因为 C 和 C++ 中的浮点文本默认为 double
类型。如果添加f
,则为浮点数。浮点 epxression 的结果是"更大"类型。双精度表达式和整数的结果仍然是双精度表达式,int 和 float 将是浮点数。因此,表达式的结果要么是浮点数,要么是双精度数。
好的,但我不想四舍五入到零。我想四舍五入到最接近的数字。
若要解决此问题,请在将结果转换为整数之前将结果添加一半:
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);
}
> 1.0 被解释为双精度值,而不是编译器将 1.0f 视为浮点数。
f 后缀只是告诉编译器哪个是浮点数,哪个是双精度数。
顾名思义,双精度精度是浮点数的 2 倍。通常,双精度具有 15 到 16 个十进制数字的精度,而浮点数只有 7
。这种精度损失可能导致截断误差更容易浮出水面
请参阅 MSDN (C++(
发生这种情况的原因是使用double
时更精确的结果,即 1.0
.
尝试对结果进行四舍五入,这将导致转换后更精确的积分结果:
hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()) + 0.5);
请注意,在它之后添加 0.5
并截断 int
将导致结果四舍五入,因此当您的结果17.999...
时,它将变为 18.499...
,这将被截断为 18
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 当我的 if 条件计算结果为 false 时,我的 else 块将不会执行
- 为什么组合的上限和下限比较的计算结果总是为 true?
- 为什么'typeid(x) == typeid(y)'的计算结果为 true,其中 'x' 和 'y' 分别是 T 和 T& 类型的 id-表达式?
- 我们如何并行运行算法的 n 个实例并以有效的方式计算结果函数的平均值?
- Fmod 函数清楚地输出一个预期的双精度值,但 if(fmod == 预期的双精度值)的计算结果不是 true
- WebGL2 和 C++ 上的浮点计算结果不同
- 术语的计算结果不是采用0个参数的函数
- 错误 C2064:术语的计算结果不是采用 3 个参数的函数
- 在C++中,是否可以编写一个条件的lambda,即只是一个计算结果为真或假的条件
- C++ 函数指针的计算结果为 1
- 为什么 02000 的计算结果为 1024
- 如何让编译器忽略这个计算结果为 false 的 if-constexpr?
- 为什么需要 FPU 重置以防止 NaN 结果传播到下一个计算结果?
- C++:术语的计算结果不是采用 1 个参数的函数
- 如果满足嵌套条件,则计算结果未显示结果C
- 为什么这个条件运算符的计算结果为 int?
- 在线程错误 C2064 中:term 的计算结果不为 0 个参数的函数
- 错误 C2064:term 的计算结果不是采用 1 个参数的函数 - 关于线程的一些东西
- 提升线程:术语的计算结果不为 0 个参数