首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IEEE-754:“最小”溢出条件

IEEE-754:“最小”溢出条件
EN

Stack Overflow用户
提问于 2018-08-23 21:43:40
回答 2查看 1.5K关注 0票数 2

在我开始之前,只是一些背景信息:

我正在ARM7微控制器(754 2294/01)上运行一个裸金属应用程序,该应用程序是在Keil uVision3中编译的,使用编译器标准的数学库(符合IEEE-754标准)。

问题:,我很难理解在两个单精度浮点输入之和上,到底是什么构成了“溢出”。

最初,我的印象是,如果我试图向可以用IEEE-754表示法表示的最大值中添加任何正值,则结果将生成溢出异常。

例如,假设我有:

代码语言:javascript
复制
 a = 0x7f7fffff (ie. 3.4028235..E38);
 b = 0x3f800000 (ie. 1.0)

我预计,将这两个值相加将导致IEEE-754中定义的溢出。令我惊讶的是,结果只是返回'a‘的值,无一例外地被标记。

所以我想,由于精度(或者分辨率,如果你喜欢的话)随着被表示的值的增加而降低,在这种情况下,它的值'1‘很可能被有效地四舍五入到0,因为它是相对不重要的。

因此,提出了一个问题:,在这种情况下,最小的'b‘值是什么,会导致溢出异常?它是否取决于IEEE-754的具体实现?

在这种特殊情况下,它可能像我一样简单,不知道如何确定最小的“重要”精度,但是根据下面的代码,为什么第二个和会导致溢出而不是第一个?

代码语言:javascript
复制
static union sFloatConversion32
{
     unsigned int unsigned32Value;
     float floatValue;
} sFloatConversion32;

t_bool test_Float32_Addition(void)
{
   float a;
   float b;
   float c;

   sFloatConversion32.unsigned32Value = 0x7f7fffff;
   a = sFloatConversion32.floatValue;

   sFloatConversion32.unsigned32Value = 0x72ffffff;
   b = sFloatConversion32.floatValue;

   /* This sum returns (c = a) without overflow */
   c = a + b;

   sFloatConversion32.unsigned32Value = 0x73000000;
   b = sFloatConversion32.floatValue;

   /* This sum, however, causes an overflow exception */
   c = a + b;
}

是否有一条普遍适用的规则,以便能够提前知道(如。如果不执行sum),那么给定两个浮点数,它们的和将导致IEEE-754定义的溢出?

EN

回答 2

Stack Overflow用户

发布于 2018-08-24 05:56:28

它是否取决于IEEE-754的具体实现?

是的,并且舍入模式在当时是活动的。

考虑x before maxFLT_MAX之间的步骤。

代码语言:javascript
复制
float max = FLT_MAX;
float before_max = nextafterf(max, 0.0f);
float delta = max - before_max;
printf("max:   %- 20a %.*g\n", max, FLT_DECIMAL_DIG, max);
printf("1st d: % -20a %.*g\n", delta, FLT_DECIMAL_DIG, delta);
// Typical output
max:    0x1.fffffep+127     3.40282347e+38
b4max:  0x1.fffffep+127     3.40282347e+38
1st d:  0x1p+104            2.02824096e+31

最大的float大约是float的两倍,具有相同最小的float和相同的步骤,或者是ULP。想想这个更小的float,它的所有显式精度位都被清除了,与FLOAT_MAX一样。

代码语言:javascript
复制
float m0 = nextafterf(max/2, max);
printf("m0:    %- 20a %.*g\n", m0, FLT_DECIMAL_DIG, m0);
// m0:     0x1p+127            1.70141183e+38

现在将其与FLT_EPSILON进行比较,这是从1.0到下一个更大的float的最小步骤

代码语言:javascript
复制
float eps = FLT_EPSILON;
printf("epsil: %- 20a %.*g\n", eps, FLT_DECIMAL_DIG, eps);
// Output
// epsil:  0x1p-23             1.1920929e-07

注意,比率delta/m0FLT_EPSILON

代码语言:javascript
复制
float r = delta1/m0;
printf("r:     %- 20a %.*g\n", r, FLT_DECIMAL_DIG, r);
// r:      0x1p-23             1.1920929e-07

考虑典型的四舍五入方式,舍入到最近,联系到偶数。

现在让我们尝试将1/2*delta1添加到FLOAT_MAX中,然后尝试添加下一个较小的float

代码语言:javascript
复制
sum = max + delta1/2;
printf("sum:        % -20a %.*g\n", sum, FLT_DECIMAL_DIG, sum);
sum = nextafterf(sum, 0);
printf("sum:        % -20a %.*g\n", sum, FLT_DECIMAL_DIG, sum);
// sum:         inf                 inf
// sum:         0x1.fffffep+127     3.40282347e+38

IEEE-754:“最小”溢出条件

如果是关于FLT_MAX*1/2*1/2*FLOAT_EPSILON,我们可以看到最小的增量。

代码语言:javascript
复制
float small = FLT_MAX*0.25f*FLT_EPSILON;
printf("small: %- 20a %.*g\n", small, FLT_DECIMAL_DIG, small);
printf("sum:        % -20a %.*g\n", max+small, FLT_DECIMAL_DIG, max+small);
small = nextafterf(small, max);
printf("sum:        % -20a %.*g\n", max+small, FLT_DECIMAL_DIG, max+small);
// sum:         0x1.fffffep+127     3.40282347e+38
// sum:         inf                 inf

考虑到float的各种可能编码,您的结果可能有所不同,但是这种方法给出了如何确定导致溢出的最小增量的概念。

票数 1
EN

Stack Overflow用户

发布于 2018-08-23 22:19:52

运行这个程序足够长的时间,看看会发生什么:

代码语言:javascript
复制
float x = 10000000.0f;
while(1)
{
    printf("%f\n", x);
    x += 1.0f;
}

我想它会回答你的问题。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51994695

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档