从一个浮点数static_cast
到一个整数将简单地去除数字的小数点。例如,static_cast<int>(13.9999999)
产生13
。
并非所有整数都可以表示为浮点数。例如,内部最接近13,000,000的float
可以是:12999999.999999
。
在这种假设的情况下,我期望得到以下结果的意外结果:
const auto foo = 12'999'999.5F;
const auto bar = static_cast<long long>(ceil(foo));
我的假设是,这样的故障确实会在某个时刻发生,即使不一定是13,000,000。我只想知道我可以信任
static_cast<long long>(ceif(foo))
的范围吗? 最佳答案
例如,内部最接近13,000,000的浮点数可能是:12999999.999999。
这在任何常规浮点格式中都是不可能的。数字的浮点表示等效于M•be,其中b是固定基数(例如,二进制浮点为2),M和e是对其值有一定限制的整数。为了表示一个类似于13,000,000-x的值,其中x是小于1的某个正值,e必须为负(因为对于非负e,M•be是整数)。如果是这样,则M•b0是大于M•be的整数,因此它大于13,000,000,因此13,000,000可以表示为M'•b0,其中M'是小于M的正整数,因此适合M的允许值范围(任何常规浮点格式)。 (也许某些奇怪的浮点格式可能会在M或e上施加一个奇怪的范围来阻止这种情况,但正常格式无法做到这一点。)
关于您的代码:
auto test = 0LL;
const auto floater = 0.5F;
for(auto i = 0LL; i == test; i = std::ceil(i + floater)) ++test;
cout << test << endl;
当
i
为8,388,608时,8,388,608 + .5的数学结果为8,388,608.5。这在您的系统上无法用float
格式表示,因此已四舍五入为8,388,608。 ceil
是8,388,608。此时,test
为8,388,609,因此循环停止了。因此,此代码无法证明8,388,608.5是可表示的,而8,388,609不是。如果执行以下操作,行为似乎恢复正常:ceil(8'388'609.5F)将正确返回8,388,610。
8,388,609.5在您的系统上不能以
float
格式表示,因此已通过“四舍五入到最接近的位数”规则进行了四舍五入。两个最接近的可表示值分别是8,388,609和8,388,610。由于它们之间的距离相等,因此结果为8,388,610。该值传递给ceil
,它当然返回了8,388,610。在Visual Studio 2015上,我得到了8,388,609,这是一个可怕的小安全范围。
在IEEE-754基本32位二进制格式中,从-16,777,216到+16,777,216的所有整数都是可表示的,因为该格式具有24位有效数字。
关于c++ - static_casting ceil的结果何时会损害结果?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48117170/