浮点溢出和不精确
Floating point overflow and inexactness
我发现在处理 Intel 硬件上的浮点错误时存在一些不一致,我想知道这是 Intel 硬件错误还是只是浮点运算工作的一般方式。场景:
1) 10000 + 最大浮点数 = 3.40282e+38
产生的错误:FE_INEXACT
2) 最大浮点数 + 最大浮点数 = inf
错误:FE_OVERFLOW、FE_INEXACT
3) 1.1 * 最大浮点数 = 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();
}
Scenario 1 is inconsistent with other two because I was exceeding float range but I did not get overflow like in case 2 and 3.
总和 10000 + maxfloat
不能精确表示,因此 FE_INEXACT
。相反,总和是四舍五入的。舍入选择包括最大的有限数 maxfloat
和下一个最大的有限数 "as if" 它可以用额外的指数范围表示。舍入到最近,总和四舍五入到 maxfloat
因为它更接近。
在情况 2 和 3 中,总和四舍五入到或高于下一个最大的有限 "as if" 数字。由于四舍五入和meets/exceeds这个数,返回无穷大。
下面是显示最后 3 个有限浮点数的数字行,包括 FLT_MAX
。
如果 float 有更多的指数范围,FLT_MAX
之后的下两个数字将是右边的 2 个:'FLT_MAX
next "as if"' 和 unnamed.
"Half-way" 介于 FLT_MAX
和下一个最大的有限 "as if" 数字之间。
当总和大于 FLT_MAX
但小于 "Half-way" 时,四舍五入会导致 FLT_MAX
(情况 1)。当总和更大时,结果为无穷大。 (案例2,3).
有限范围上限的有限结果的舍入方式是:
- 计算如果指数范围永远持续下去,将产生什么可表示的数字。
- 如果该结果超出实际范围,则产生无穷大并报告溢出和不准确。否则,生成该数字(如果需要四舍五入,则报告不准确)。
这里的逻辑是,如果四舍五入会产生指数范围内的数字,那么就不会溢出(即使数学结果超过了最大可表示的有限数,只要正常四舍五入就会带来它回到范围内)。
IEEE-754 32位二进制的最大有限值为2128−2104。如果指数范围是无限的,下一个可重复的值将是 2128.
我们先来看案例2和案例3。在情况 2 中,我们将最大有限值加到自身,所以我们有 (2128−2104) + (2128−2104)。在数学上,这是 2129−2105。如果指数范围是无限的,这将是可表示的,因此不需要四舍五入;这将是结果。那么这个数的指数超出了实际的指数范围,所以产生了无穷大。
在情况 3 中,我们将最大有限值乘以 1.1(实际上必须是接近 1.1 的值,因为 1.1 本身不可表示)。所以我们有大约 (2128−2104) • 1.1。实数结果将超过 2128,因此,如果指数范围是无限的,浮点结果将超过 2128 .该数字的指数超出实际指数范围,因此产生无穷大。
现在 return 到情况 1。我们将 10,000 添加到最大有限值,所以我们有 10,000 + (2128−2104 ), 或 2128−2104+10,000。最大有限值 (2128−2104) 和下一个可以用无限指数范围表示的值 (2128) 是 2128−2105。我们的实数结果 2128−2104+10,000 小于该中点。因此,当使用舍入到最近的偶数时,我们会将结果向下舍入为 2128−2104。该数字在实际指数范围内(其指数为 127——我们刚刚将其表示为 2128 减去一位而不是 2127 加很多)。结果就是这样。
因此10,000加上最大有限值产生最大有限值。它只是“一点点”超过了最大有限值并向下舍入。其他操作超过了最大有限值很多并被四舍五入。
我发现在处理 Intel 硬件上的浮点错误时存在一些不一致,我想知道这是 Intel 硬件错误还是只是浮点运算工作的一般方式。场景:
1) 10000 + 最大浮点数 = 3.40282e+38 产生的错误:FE_INEXACT
2) 最大浮点数 + 最大浮点数 = inf 错误:FE_OVERFLOW、FE_INEXACT
3) 1.1 * 最大浮点数 = 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();
}
Scenario 1 is inconsistent with other two because I was exceeding float range but I did not get overflow like in case 2 and 3.
总和 10000 + maxfloat
不能精确表示,因此 FE_INEXACT
。相反,总和是四舍五入的。舍入选择包括最大的有限数 maxfloat
和下一个最大的有限数 "as if" 它可以用额外的指数范围表示。舍入到最近,总和四舍五入到 maxfloat
因为它更接近。
在情况 2 和 3 中,总和四舍五入到或高于下一个最大的有限 "as if" 数字。由于四舍五入和meets/exceeds这个数,返回无穷大。
下面是显示最后 3 个有限浮点数的数字行,包括 FLT_MAX
。
如果 float 有更多的指数范围,FLT_MAX
之后的下两个数字将是右边的 2 个:'FLT_MAX
next "as if"' 和 unnamed.
"Half-way" 介于 FLT_MAX
和下一个最大的有限 "as if" 数字之间。
当总和大于 FLT_MAX
但小于 "Half-way" 时,四舍五入会导致 FLT_MAX
(情况 1)。当总和更大时,结果为无穷大。 (案例2,3).
有限范围上限的有限结果的舍入方式是:
- 计算如果指数范围永远持续下去,将产生什么可表示的数字。
- 如果该结果超出实际范围,则产生无穷大并报告溢出和不准确。否则,生成该数字(如果需要四舍五入,则报告不准确)。
这里的逻辑是,如果四舍五入会产生指数范围内的数字,那么就不会溢出(即使数学结果超过了最大可表示的有限数,只要正常四舍五入就会带来它回到范围内)。
IEEE-754 32位二进制的最大有限值为2128−2104。如果指数范围是无限的,下一个可重复的值将是 2128.
我们先来看案例2和案例3。在情况 2 中,我们将最大有限值加到自身,所以我们有 (2128−2104) + (2128−2104)。在数学上,这是 2129−2105。如果指数范围是无限的,这将是可表示的,因此不需要四舍五入;这将是结果。那么这个数的指数超出了实际的指数范围,所以产生了无穷大。
在情况 3 中,我们将最大有限值乘以 1.1(实际上必须是接近 1.1 的值,因为 1.1 本身不可表示)。所以我们有大约 (2128−2104) • 1.1。实数结果将超过 2128,因此,如果指数范围是无限的,浮点结果将超过 2128 .该数字的指数超出实际指数范围,因此产生无穷大。
现在 return 到情况 1。我们将 10,000 添加到最大有限值,所以我们有 10,000 + (2128−2104 ), 或 2128−2104+10,000。最大有限值 (2128−2104) 和下一个可以用无限指数范围表示的值 (2128) 是 2128−2105。我们的实数结果 2128−2104+10,000 小于该中点。因此,当使用舍入到最近的偶数时,我们会将结果向下舍入为 2128−2104。该数字在实际指数范围内(其指数为 127——我们刚刚将其表示为 2128 减去一位而不是 2127 加很多)。结果就是这样。
因此10,000加上最大有限值产生最大有限值。它只是“一点点”超过了最大有限值并向下舍入。其他操作超过了最大有限值很多并被四舍五入。