从一个浮点数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/

10-10 23:08