如果结果不正常,可以设置浮点状态标志FE_UNDERFLOW吗? [英] Can the floating-point status flag FE_UNDERFLOW set when the result is not sub-normal?

查看:66
本文介绍了如果结果不正常,可以设置浮点状态标志FE_UNDERFLOW吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在研究浮点异常状态标志时,我遇到了一个奇怪的情况:状态标志FE_UNDERFLOW在不期望的时候置位.

While investigating floating-point exception status flags, I came across the curious case of a status flag FE_UNDERFLOW set when not expected.

这类似于何时发生下溢?却陷入了可能是C规范问题或FP硬件缺陷.

This is similar to When does underflow occur? yet goes into a corner case that may be a C specification issue or FP hardware defect.

// pseudo code
//                       s bias_expo implied "mantissa"
w = smallest_normal;  // 0 000...001 (1)     000...000
x = w * 2;            // 0 000...010 (1)     000...000
y = next_smaller(x);  // 0 000...001 (1)     111...111
round_mode(FE_TONEAREST);
clear_status_flags();
z = y/2;              // 0 000...001 (1)     000...000

FE_UNDERFLOW is set!?

我没想到将FE_UNDERFLOW设置为上面的z是正常的,而不是次要的.
我希望早期的浮点运算结果不合标准且精度下降时会出现FE_UNDERFLOW.在这种情况下,会损失精度.

I did not expect FE_UNDERFLOW to be set as z above is normal, not a sub-normal.
I expect FE_UNDERFLOW when the result of an earlier floating-point operation was subnormal with a loss of precision. In this case there is a loss of precision.

我用floatlong double进行了尝试,并得到了相同的结果.

I tried this with my float and long double and had the same result.

经过大量调查,我注意到__STDC_IEC_559__未定义 .

After much investigation, I noted that __STDC_IEC_559__ is not defined.

问题

  1. 如果定义了__STDC_IEC_559__,在这种情况下下溢的正确状态是什么?

  1. If __STDC_IEC_559__ is defined, what is the correct state of underflow in this case?

在缺少定义的__STDC_IEC_559__的情况下,我是否坚持未定义__STDC_IEC_559__的实现不需要符合这些要求" 规范." C11或是否有一些C规范表明此结果不正确?

With lack of a defined __STDC_IEC_559__ am I stuck with "Implementations that do not define __STDC_IEC_559__ are not required to conform to these specifications." C11 or is there some C specification that indicates this result is incorrect?

由于这肯定是我的硬件(处理器)导致的,因此您的结果可能会有所不同,这很有趣.

Since this is certainly a result of my hardware (processor), your result may differ and that would be interesting to know.


以下是一些演示此问题的测试代码.起初我怀疑是因为FLT_EVAL_METHOD = 2在我的计算机上,但是后来我尝试使用long double进行类似的代码并得到相同的结果.


Follows is some test code that demos this. At first I suspected it is because FLT_EVAL_METHOD = 2 on my machine, yet then I tried similar code with long double and the same result.

// These 2 includes missing in original post, yet in my true test code
#include <float.h>
#include <math.h>

#include <fenv.h>
#include <stdio.h>
#include <stdint.h>

#define N (sizeof excepts/sizeof excepts[0])
void Report_IEC_FP_exception_status_flags(const char *s) {
  printf("%s", s);
  int excepts[] = { //
      FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW, };
  const char *excepts_str[N] = { //
      "FE_DIVBYZERO", "FE_INEXACT", "FE_INVALID", "FE_OVERFLOW", "FE_UNDERFLOW", };
  int excepts_val[N];

  for (unsigned i = 0; i < N; i++) {
    excepts_val[i] = fetestexcept(excepts[i]);
  }
  for (unsigned i = 0; i < N; i++) {
    if (excepts_val[i]) printf(" %s", excepts_str[i]);
  }
  printf("\n");
  fflush(stdout);
}
#undef N

void test2(float f, int round_mode, const char *name) {
  union {
    float f;
    uint32_t u32;
    } x = { .f = f};

  printf("x:%+17a %08lX normal:%c round_mode:%d %s\n", //
  f, (unsigned long) x.u32, isnormal(f) ? 'Y' : 'n', round_mode, name);
  if (feclearexcept(FE_ALL_EXCEPT)) puts("Clear Fail");
  Report_IEC_FP_exception_status_flags("Before:");

  f /= 2;

  Report_IEC_FP_exception_status_flags("After :");
  printf("y:%+17a %08lX normal:%c\n\n", 
      f,(unsigned long) x.u32, isnormal(f) ? 'Y' : 'n');
}

驱动程序

// In same file as above
int main(void) {
  #ifdef __STDC_IEC_559__
    printf("__STDC_IEC_559__ = %d\n", __STDC_IEC_559__);
  #else
    printf("__STDC_IEC_559__ = not define\n");
  #endif

  float f = FLT_MIN;
  printf("FLT_EVAL_METHOD = %d\n", FLT_EVAL_METHOD);
  printf("FLT_MIN:%+17a\n", f);
  f *= 2.0f;
  test2(f, FE_TONEAREST, "FE_TONEAREST");
  f = nextafterf(f, 0);
  test2(f, FE_TONEAREST, "FE_TONEAREST");   // *** problem? ***
  f = nextafterf(f, 0);
  test2(f, FE_TONEAREST, "FE_TONEAREST");
}

输出

__STDC_IEC_559__ = not define
FLT_EVAL_METHOD = 2
FLT_MIN:        +0x1p-126
x:        +0x1p-125 01000000 normal:Y round_mode:0 FE_TONEAREST
Before:
After :
y:        +0x1p-126 01000000 normal:Y

x: +0x1.fffffep-126 00FFFFFF normal:Y round_mode:0 FE_TONEAREST
Before:
After : FE_INEXACT FE_UNDERFLOW                *** Why FE_UNDERFLOW? ***
y:        +0x1p-126 00FFFFFF normal:Y          *** Result is normal  ***

x: +0x1.fffffcp-126 00FFFFFE normal:Y round_mode:0 FE_TONEAREST
Before:
After :
y: +0x1.fffffcp-127 00FFFFFE normal:n

参考

IEEE_754

实施说明:

GNU C11(GCC)版本6.4.0(i686-pc-cygwin) 由GNU C版本6.4.0,GMP版本6.1.2,MPFR版本3.1.5-p10,MPC版本1.0.3,isl版本0.14或0.13编译

GNU C11 (GCC) version 6.4.0 (i686-pc-cygwin) compiled by GNU C version 6.4.0, GMP version 6.1.2, MPFR version 3.1.5-p10, MPC version 1.0.3, isl version 0.14 or 0.13

glibc 2.26发布了.

glibc 2.26 released.

Intel Xeon W3530,64位操作系统(Windows 7)

Intel Xeon W3530, 64-bit OS (Windows 7)

[次要更新]作为32位十六进制数字的商的说明性打印应使用y.u32.这不会更改被测功能

[Minor Update] The illustrative print of the quotient as an 32-bit hex number should have used y.u32. This does not change the function under test

// printf("y:%+17a %08lX normal:%c\n\n", 
//    f,(unsigned long) x.u32, isnormal(f) ? 'Y' : 'n');
union {
  float f;
  uint32_t u32;
} y = { .f = f};
printf("y:%+17a %08lX normal:%c\n\n", 
    f,(unsigned long) y.u32, isnormal(f) ? 'Y' : 'n');
//                    ^^^^^

推荐答案

尽管不打算作为自我解答,来自各种评论者 @ nwellnhof ,进一步的研究导致:

Although not intended as a self answer, input from various commenters @John Bollinger, @nwellnhof and further research leads to:

结果不正常时,是否可以设置浮点状态标志FE_UNDERFLOW?

Can the floating-point status flag FE_UNDERFLOW set when the result is not sub-normal?

,在狭窄的情况下.见下文.

Yes, in narrow situations. See below.

下溢"发生在以下情况:

"Underflow" occurs when:

如果数学结果的大小如此之小,以至于在没有特殊舍入误差的情况下,无法在指定类型的对象中表示数学结果,则结果将下溢. C11 7.12.1错误条件的处理

The result underflows if the magnitude of the mathematical result is so small that the mathematical result cannot be represented, without extraordinary roundoff error, in an object of the specified type. C11 7.12.1 Treatment of error conditions

上面的z = y/2;是1)不精确(由于四舍五入)和2)可能被认为太小".

The z = y/2; above is 1) inexact (due to rounding) and 2) maybe considered "too small".

数学

可以认为z = y/2;经历了两个阶段:除法和舍入.数学商具有无限的精度,小于最小的标准数字FLT_MIN且大于最大的 sub -正常数字 nextafterf(FLT_MIN,0).根据取整模式,最终答案是这两个之一.在FE_TONEAREST中,为z分配了一个正常编号FLT_MIN.

The z = y/2; can be thought of going through 2 stages: dividing and rounding. The mathematical quotient, with unlimited precision, is less than the smallest normal number FLT_MIN and more than the greatest sub-normal number nextafterf(FLT_MIN,0). Depending on rounding mode, the final answer is either one of those two. With FE_TONEAREST, z is assigned FLT_MIN, a normal number.

规范

下面的C规范以及IEC 60559表示

The C spec below and to IEC 60559 indicate

下溢"每当结果很小(本质上是次正规或零)并且遭受准确性损失时,都会引发浮点异常. 358 C11§F.107.
358 IEC 60559允许不同的下溢定义.它们都产生相同的值,但是引发浮点异常的时间有所不同.

The "underflow" floating-point exception is raised whenever a result is tiny (essentially subnormal or zero) and suffers loss of accuracy.358 C11 §F.10 7.
358 IEC 60559 allows different definitions of underflow. They all result in the same values, but differ on when the floating-point exception is raised.

允许使用两种定义来确定微小"条件:在四舍五入之前或之后将无限精确的结果四舍五入到工作精度,且指数无界.

Two definitions were allowed for the determination of the 'tiny' condition: before or after rounding the infinitely precise result to working precision, with unbounded exponent.

754r的附录U建议仅将四舍五入后的细小和不精确的精度降低作为下溢信号的原因. Wiki参考

Annex U of 754r recommended that only tininess after rounding and inexact as loss of accuracy be a cause for underflow signal. wiki reference

(我的重点)

问与答; A

  1. 如果定义了 STDC_IEC_559 ,在这种情况下下溢的正确状态是什么?
  1. If STDC_IEC_559 is defined, what is the correct state of underflow in this case?

在这种情况下,下溢标志可以设置或保留.要么遵守.但是,有一个偏好设置是不设置下溢标志.

The underflow flag may be set or left alone in this case. Either complies. There is a preference though, for not setting the underflow flag.

2由于缺少已定义的 STDC_IEC_559 ,我坚持未定义 STDC_IEC_559 的实现不需要符合这些规范." C11还是有一些C规范表明此结果不正确?

2 With lack of a defined STDC_IEC_559 am I stuck with "Implementations that do not define STDC_IEC_559 are not required to conform to these specifications." C11 or is there some C specification that indicates this result is incorrect?

下溢标志的设置结果不正确. FP规范允许这种行为.它还允许不设置下溢标志.

The setting of the underflow flag result in not incorrect. The FP spec allows this behavior. It also allows to not set the underflow flag.

3由于这肯定是我的硬件(处理器)导致的,因此您的结果可能会有所不同,这很有趣.

3 Since this is certainly a result of my hardware (processor), your result may differ and that would be interesting to know.

在另一个平台上,其中__STDC_IEC_559__ = not defineFLT_EVAL_METHOD = 0都设置了FE_INEXACT FE_UNDERFLOW标志,就像在上述第一种情况下一样.该问题适用于float, double, long double.

On another platform, where __STDC_IEC_559__ = not define and FLT_EVAL_METHOD = 0, the FE_INEXACT FE_UNDERFLOW flags were both set, just like in the above tst case. The issue applies to float, double, long double.

如果数学答案位于灰色之间",则为否".在下面的区域中,将根据其值和舍入模式将其向下舍入为次法线double或向上舍入为法线double DBL_MIN.如果四舍五入,则必须设置FE_UNDERFLOW.如果四舍五入,则可以根据是否应用微小"条件的时间设置是否设置FE_UNDERFLOW.

If the mathematical answer lies in the grey "Between" zone below, it will get rounding down to a sub-normal double or up to the normal double DBL_MIN depending on its value and rounding mode. If rounded down, then FE_UNDERFLOW is certainly set. If rounded up, then FE_UNDERFLOW may be set or not depending on when determination of the 'tiny' condition is applied.

这篇关于如果结果不正常,可以设置浮点状态标志FE_UNDERFLOW吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆