__builtin_isnanl() and invalid x87 80-bit floating point numbers

Liu Hao lh_mouse@126.com
Sat May 13 03:06:00 GMT 2017


On 2017/5/13 10:25, Vincent Lefevre wrote:
> On 2017-05-12 23:46:09 +0800, Liu Hao wrote:
> But if you do this, you're out of scope of the standards.
> 
> Moreover, I suppose that you will also get a floating-point exception
> on a signaling NaN, in which case, on this example, this isn't
> distinguishable from a signaling NaN.
A QNaN doesn't generate an exception regardless of the x87 control word.

To make a QNaN, replace the last three bytes of `data` with `0xc0, 0xff, 
0x7f`. The last example would then exit normally with the output 'nan'. 
I will show an example later.

> But the goal of Intel's x87 80-bit format and the IEEE 754-1985 spec
> was to regard this format as a conforming double-extended format.
> And AFAIK, the intent of IEEE 754-2008 was not to break this.
> 
>> I don't think ISO C forbids existence of `trap representation` of
>> `long double`.
> 
> Anyway, this is not a trap representation as shown above.
It does generate an exception so why do you think it is not a trap 
representation?

> FXAM is neither an IEEE 754 operation, nor an ISO C operation.
> 
> Let's try ==, which corresponds to the IEEE 754 equality operator:
> 
> #include <stdio.h>
> 
> int main (void)
> {
>    long double ld = 0;
>    unsigned char data[10] = {
>      0x5b, 0x01, 0x04, 0x5e, 0x85, 0x00, 0x00, 0x00, 0xd8, 0x59
>    };
>    __builtin_memcpy(&ld, data, 10);
>    printf ("NaN? %s\n", ld == ld ? "no" : "yes");
>    return 0;
> }
> 
> This gives:
> 
> NaN? yes
> 
> So, it is regarded as a NaN.
> 
Let's try `=` which corresponds to the IEEE 754 equality operator too:

-------------------------------------------------------
lh_mouse@lhmouse-dev:~$ cat test.c
#include <stdio.h>
#include <math.h>

int main (void)
{
    unsigned short fcw;
    __asm__ volatile (
      "fstcw %0; "
      "andw $-2, %0; "
      "fldcw %0; "
      : "=m"(fcw)
    );
    long double ld = 0;
    unsigned char data[10] = {
      0x5b, 0x01, 0x04, 0x5e, 0x85, 0x00, 0x00, 0x00, 0xd8, 0x59
    };
    __builtin_memcpy(&ld, data, 10);
    long double y = 1;
    y = ld;
    printf ("%Lg\n", y);
    return 0;
}
lh_mouse@lhmouse-dev:~$ gcc test.c -Wall -Wextra -pedantic -std=c99
lh_mouse@lhmouse-dev:~$ ./a.out
5.11212e+1984
-------------------------------------------------------

Then replace it with a QNaN:

-------------------------------------------------------
lh_mouse@lhmouse-dev:~$ sed -i 's/0x00, 0xd8, 0x59/0xc0, 0xff, 0x7f/' test.c
lh_mouse@lhmouse-dev:~$ gcc test.c -Wall -Wextra -pedantic -std=c99
lh_mouse@lhmouse-dev:~$ ./a.out
nan
-------------------------------------------------------

Then replace it with a SNaN:

-------------------------------------------------------
lh_mouse@lhmouse-dev:~$ gcc test.c -Wall -Wextra -pedantic -std=c99
lh_mouse@lhmouse-dev:~$ ./a.out
nan
-------------------------------------------------------

So, it is not regarded as a NaN.

-- 
Best regards,
LH_Mouse



More information about the Gcc-help mailing list