Menu

#367 fpclassify/isnormal can't detect denormalised floating point numbers

v1.0 (example)
open-accepted
nobody
None
5
2018-10-24
2013-12-01
Peter Bex
No

A simple program which prints the value of isnormal(4.9406564584124654417657e-324) shows 1 (also if that value is assigned to a variable declared "double" and that variable is tested):

#include <stdio.h>
#include <math.h>

int main(void) {
  double x = 4.9406564584124654417657e-324;
  printf("Normal? %d\n" isnormal(x));
  printf("Normal? %d\n" isnormal(4.9406564584124654417657e-324));
}

The program should show "Normal? 0" twice. The denormalised number has been taken from the ATF tests for fpclassify/isnormal from the NetBSD source tree.

More denormalised numbers from that test suite:

1.1125369292536006915451e-308
-5.5626846462680034577256e-309
4.9406564584124654417657e-324

This has been reported for MingW as well, and hasn't been fixed there yet either: http://sourceforge.net/p/mingw/bugs/1927/

Discussion

  • Kai Tietz

    Kai Tietz - 2013-12-02

    I tested your testcase on linux using glibc (libm), and it produces same result as we do on mingw-w64's trunk.
    In both cases isnormal is 0 (as to be expected).

     
  • Kai Tietz

    Kai Tietz - 2013-12-02
    • status: open --> pending-invalid
     
  • Kai Tietz

    Kai Tietz - 2013-12-02

    IMHO is testcase invalid.

     
  • Kai Tietz

    Kai Tietz - 2013-12-02
    • status: pending-invalid --> open-accepted
     
  • Kai Tietz

    Kai Tietz - 2013-12-02

    So, found the issue. It affects 32-bit only.
    For 32-bits result is 1, for 64-bit result is 0. So the bug seems to be on 32-bit side.

     
  • FX

    FX - 2017-01-05

    The 32-bit code, for double, is in effect the following:

    #include <stdio.h>
    
    #define FP_NAN      0x0100
    #define FP_NORMAL   0x0400
    #define FP_ZERO     0x4000
    int __fpclassify (double x)
    {
      unsigned short sw;
      __asm__ __volatile__ ("fxam; fstsw %%ax;" : "=a" (sw): "t" (x));
      return sw & (FP_NAN | FP_NORMAL | FP_ZERO );
    }
    
    int main (void)
    {
      double x = 4.9406564584124654417657e-324;
      printf("%d\n", __fpclassify(x) == FP_NORMAL);
    }
    

    It might make sense to use (when available) GCC's type-generic __builtin_fpclassify (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) instead of the current __fpclassify in mingw-w64.

     
  • Sisyphus

    Sisyphus - 2018-10-24

    With my 32-bit mingw-w64 port of gcc-8.1.0, I still experience this issue iff optimization is enabled.
    There's no problem with the 64-bit port.

    Here's the demo :

    #include <stdio.h>
    #include <math.h>
    
    int main(void) {
      double x = 1e-320;
      if(isnormal(x)) printf("wtf\n");
      else printf("ok\n");
      printf("%x\n", fpclassify(x));
      printf("%x\n", __fpclassify(x));
    /* printf("%x\n", __builtin_fpclassify(x)); *//* error */
    }
    

    When built without optimization it correctly outputs:

    ok
    4400
    4400

    But when built with O1 (or higher) optimization it outputs:

    wtf
    400
    400

        I was curious to see how __builtin_fpclassify fared but apparently
        it's not a drop-in replacement for fpclassify.
        The error produced was "too few arguments to function __builtin_fpclassify".
    

    Cheers,
    Rob

     

Log in to post a comment.

MongoDB Logo MongoDB