我在处理英特尔硬件上的浮点错误时发现了一些不一致之处,我想知道这是英特尔硬件错误还是浮点算术工作原理的一般方式。场景:
1)10000 +最大流通量= 3.40282e + 38 产生错误:FE_INEXACT
2)maxfloat + maxfloat = inf 错误:FE_OVERFLOW,FE_INEXACT
3)1.1 * maxfloat = inf 错误:FE_OVERFLOW,FE_INEXACT
方案1与其他两个方案不一致,因为我超出了浮动范围,但没有像情况2和3那样溢出。
我无法理解为什么我没有溢出,并且在第一种情况下数字只是饱和,而在第二和第三个数字没有饱和的情况下,我会溢出。
#include <iostream>
#include <limits>
#include <cstdio>
#include <cfenv>
void print_error() {
const int err = fetestexcept(FE_ALL_EXCEPT);
if (err & FE_INVALID) cout << "FE_INVALID " << endl;
if (err & FE_DIVBYZERO) cout << "FE_DIVBYZERO "<< endl;
if (err & FE_OVERFLOW) cout << "FE_OVERFLOW "<< endl;
if (err & FE_UNDERFLOW) cout << "FE_UNDERFLOW " << endl;
if (err & FE_INEXACT) cout << "FE_INEXACT " << endl;
cout << endl;
}
int main() {
feclearexcept(FE_ALL_EXCEPT);
cout << numeric_limits<float>::max() + 100000.0f << endl;
print_error();
feclearexcept(FE_ALL_EXCEPT);
cout << numeric_limits<float>::max() + numeric_limits<float>::max() << endl;
print_error();
feclearexcept(FE_ALL_EXCEPT);
cout << 1.1f*numeric_limits<float>::max() << endl;
print_error();
}
答案 0 :(得分:3)
方案1与其他两个方案不一致,因为我超出了浮动范围,但没有像情况2和3那样溢出。
和10000 + maxfloat
不能精确表示,因此FE_INEXACT
。相反,总和被四舍五入。舍入选择包括最大有限数maxfloat
和第二个最大有限数“好像”,可以用其他指数范围表示。四舍五入到最接近值时,总和四舍五入到maxfloat
,因为它更接近。
在情况2和3中,总和四舍五入到或大于此下一个最大的有限“好像”数字。由于四舍五入后的总和达到/超过此数字,因此将返回无穷大。
下面是一条数字线,显示了最后3个有限浮点,包括FLT_MAX
。
如果float的指数范围更大,则FLT_MAX
之后的下2个数字将是右边的2:'FLT_MAX
下一个“好像””且未命名。
“半程”在FLT_MAX
和下一个最大的有限“好像”数字之间。
当总和大于FLT_MAX
但小于“半路”时,四舍五入到最接近的结果为FLT_MAX
(情况1)。当总和更大时,结果为无穷大。 (案例2,3)。
答案 1 :(得分:2)
在有限范围的上限处对有限结果进行舍入的方式是:
这里的逻辑是,如果四舍五入总会产生一个在指数范围内的数字,那么就不会有溢出(即使数学结果超出了最大可表示的有限数,只要正常的四舍五入就可以将其取回)范围)。
IEEE-754 32位二进制文件中的最大有限值为2 128 -2 104 。如果指数范围不受限制,则下一个可表示的值为2 128 。
首先让我们看一下案例2和案例3。在情况2中,我们将最大值添加到自身,所以我们有(2 128 −2 104 )+(2 128 −2 104 )。从数学上来说,这是2 129 −2 105 。如果指数范围是无界的,这将是可表示的,因此不需要四舍五入;这将是结果。然后该数字的指数超出了实际的指数范围,因此将产生无穷大。
在情况3中,我们将最大有限值乘以1.1(由于1.1本身无法表示,因此它实际上必须是接近1.1的值)。因此,我们大约有(2 128 −2 104 )•1.1。实数结果将超过2 128 ,因此,如果指数范围不受限制,则浮点结果将超过2 128 。该数字的指数超出了实际的指数范围,因此将产生无穷大。
现在返回案例1。我们将10,000加到最大有限值,所以我们得到10,000 +(2 128 −2 104 )或2 128 −2 104 +10,000。最大有限值(2 128 −2 104 )和下一个可以无界指数范围表示的值(2 128 )是2 128 −2 105 。我们的实数结果2 128 −2 104 +10,000,小于该中点。因此,当使用最接近的四舍五入关系时,我们会将结果四舍五入为2 128 −2 104 。该数字在实际指数范围内(指数为127,我们只是将其表示为2 128 减去一点,而不是2 127 加很多)。结果就是这样。
因此10,000加上最大有限值将产生最大有限值。它仅“超过一点”超过了最大有限值,并被四舍五入。其他操作超出了最大有限值很多,并被四舍五入。