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

When exploring floating point exception status flags, I came across a curious case with the status flag FE_UNDERFLOW, if not expected.

This is similar to When does a thread overflow occur? still goes into the angular register, which may be a C specification issue or a 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!?

I did not expect it to FE_UNDERFLOWbe set as zabove normal, not sub-normal.
I expect the FE_UNDERFLOWresultAn earlier floating point operation was subnormal with loss of precision. In this case, a loss of accuracy occurs.

float long double .

, __STDC_IEC_559__ .

  • __STDC_IEC_559__, underflow ?

  • __STDC_IEC_559__ am ", __STDC_IEC_559__, . "C11 - C, , ?

  • , , (), .


, . , , FLT_EVAL_METHOD = 2 , long double .

// 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');
}

Driver

// 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

glibc 2.26 .

Intel Xeon W3530, 64- (Windows 7)


[ ] 32- y.u32.

// 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');
//                    ^^^^^
+6
1

, @ , @nwellnhof, :

FE_UNDERFLOW , ?

, . . .


"Underflow" , :

, , . C11 7.12.1

z = y/2; 1) (- ) 2) " ".


Math

z = y/2; , 2 : . FLT_MIN , nextafterf(FLT_MIN,0), , . FE_TONEAREST, z FLT_MIN, .

Spec

C IEC 60559

"underflow" , ( ) . 358 C11 §F.10 7.
358 IEC 60559 . , , .

"" : .

U of 754r , , , . wiki

( )


Q A

  • STDC_IEC_559, ?

. . , underflow.

2 STDC_IEC_559 am, ", STDC_IEC_559, ". C11 - C, , ?

. FP . underflow.

3 , , (), , .

, __STDC_IEC_559__ = not define FLT_EVAL_METHOD = 0, FE_INEXACT FE_UNDERFLOW , tst-. float, double, long double.


"" , - double double DBL_MIN . , FE_UNDERFLOW . , FE_UNDERFLOW , "".

Numeric string near DBL_MIN

+2

All Articles