hax*_*por 4 c++ floating-point double floating-accuracy
我有以下代码行.
hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()));
Run Code Online (Sandbox Code Playgroud)
void onBeingHit(int decHP) 方法接受整数并更新健康点.float getDefensePercent() method是一个getter方法,返回英雄的防御百分比.ENEMY_ATTACK_POINT是一个定义为的宏常数因子#define ENEMY_ATTACK_POINT 20.让我们说hero->getDefensePercent()回报0.1.所以计算是
20 * (1.0 - 0.1) = 20 * (0.9) = 18
Run Code Online (Sandbox Code Playgroud)
每当我尝试使用以下代码时(无f附加1.0)
hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()));
Run Code Online (Sandbox Code Playgroud)
我17岁了.
但是对于以下代码(f后面附后1.0)
hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0f - hero->getDefensePercent()));
Run Code Online (Sandbox Code Playgroud)
我18岁了.
这是怎么回事?是f显著要不惜任何虽然hero->getDefensePercent()已在浮动?
lee*_*mes 11
这是怎么回事?18两种情况下为什么不是整数结果?
问题是浮点表达式的结果在转换为整数值时(在两种情况下)都舍入为零.
0.1不能完全表示为浮点值(在两种情况下).编译器将转换为二进制IEEE754浮点数,并决定是向上舍入还是向下舍入为可表示的值.然后,处理器在运行时将该值相乘,并对结果进行舍入以获得整数值.
好了,但由于双方double和float那样做,为什么会18在这两种情况之一,但17在另一种情况?我糊涂了.
您的代码获取函数的结果0.1f(浮点数),然后计算20 * (1.0 - 0.1f)哪个是双表达式,而20 * (1.0f - 0.1f)浮点表达式.现在浮动版本恰好略大于18.0并且向下舍入到18,而double表达式稍微小于18.0并向下舍入到17.
如果您不确切地知道IEEE754二进制浮点数是如何从十进制数构造的,那么如果它比您在代码中输入的十进制数稍微或稍微大一点,则它几乎是随机的.所以你不应该指望这一点.不要试图通过附加f其中一个数字来解决这个问题并说"现在它可以工作,所以我把它f留在那里",因为另一个值的行为会再次不同.
为什么要依赖表达式的类型f呢?
这是因为C和C++中的浮点字面值是double默认类型.如果你添加f,它是一个浮点数.浮点epxression的结果是"更大"类型.double表达式和整数的结果仍然是double表达式,int和float也是float.因此,表达式的结果是float或double.
好的,但我不想舍入到零.我想要舍入到最接近的数字.
要解决此问题,请在将结果转换为整数之前将一半添加到结果中:
hero->onBeingHit(ENEMY_ATTACK_POINT * (1.0 - hero->getDefensePercent()) + 0.5);
Run Code Online (Sandbox Code Playgroud)
在C++ 11中,就是std::round()这样.在该标准的先前版本中,没有这样的函数可以舍入到最接近的整数.(详情请见评论.)
如果你没有std::round,你可以自己写.处理负数时要小心.转换为整数时,数字将被截断(向零舍入),这意味着负值将向上舍入而不是向下舍入.因此,如果数字是负数,我们必须减去一半:
int round(double x) {
return (x < 0.0) ? (x - .5) : (x + .5);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4187 次 |
| 最近记录: |