On Thu, Sep 19, 2013 at 6:41 AM, Roland Mainz <[email protected]> wrote:
> On Thu, Sep 5, 2013 at 5:45 AM, Roland Mainz <[email protected]> wrote:
>> On Tue, Sep 3, 2013 at 2:46 PM, Glenn Fowler <[email protected]> wrote:
>>> On Tue, 3 Sep 2013 02:50:31 +0200 Tina Harriott wrote:
>>>> I'm currently looking into a complex mathematical simulation (fluid
>>>> dynamics) and found references to NaN (Not A Number) with payloads.
>>>> The Nan values are used to represent 'no data' in the datasets and the
>>>> payloads are used for context information. The code has almost 2
>>>> million lines of code and removing the feature would be a major
>>>> effort.
>>>
>>>> As we are in the process of using ksh93 as "interface" to the
>>>> simulation using libshell we need access to Nan values and their
>>>> payloads.
>>>
>>>> Can anyone give an estimate how hard it would be to add support for
>>>> Nan payloads to ksh93?
>>>
>>> I'm aware of NaN payload but have not seen C code that
>>>         * has MIN/MAX macros for the min/max payload value for a give FP 
>>> type
>>
>> See code attached code example... the maximum is the mask-1 ... the
>> minimum is either 0 or 1... I don't remember anymore...
>>
>>>         * sets a NaN value with a specific payload
>>>         * extracts a payload from a NaN
>>> are there standard api's for this?
>>
>> Yes... the function |nan()| - see
>> http://pubs.opengroup.org/onlinepubs/009695399/functions/nan.html
>> -- snip --
>>        double nan(const char *tagp);
>>        float nanf(const char *tagp);
>>        long double nanl(const char *tagp);
>> -- snip --
>>
>> The trouble is... the exact string input is
>> compiler/libc/platforms-specific... and beyond highend HPC platforms
>> most platforms do not implement |nan()| with payload support.
>>
>> The other issue is that often compiler/libc/platforms-combinations to
>> not preserve the payload when a value is casted between _different_
>> floating-point types. That problem isn't new and has haunted HPC
>> programmers since eternity... but the solution is to simply test with
>> C99 |isnan()| and then add some copy-payload code. Since |isnan()| is
>> basically a bit-pattern test the overhead is insignificant (on SX-8X
>> that's around 8 instructions more compared to a plain cast).
>>
>> If we implement NaN's with payloads we have to make sure that _every_
>> cast between |Sfdouble| (basically a |long double|) and another
>> floating-point type is guarded with such copy-payload code... except
>> when we pass the value to a arithmetricfunction like |sin()|/|cos()|
>> etc. which (intentionally) discard the payload if they pass the Nan
>> through.
>>
>> Attached (as "nan_payload_test1_20130904_001.c.txt") is some prototype
>> code which shows now to handle NaN payloads...
>>
>> * Notes:
>> - The code explicitly requires ISO C99 semantics
>> - The code relies on |__int128_t| to handle |long double|. Originally
>> I thought about handling the code using byte-by-byte masking... but it
>> turned out that this creates a lot of mess and is endian-specific. The
>> final code may have to resort to that to be portable but for now I
>> use |__int128_t| to keep the code readable
>
> Uhm... any feedback/suggestions ? Adding Nan payload support seems to
> be easy and doesn't come with a measureable performance penalty (since
> we only do extra work *if* there is a payload, otherwise most code has
> only "wrapper" overhead) ... if there are no objections I can try my
> luck and add this to ksh93's arithmetic engine...

Attached (as "astksh20130913_nanpayload_prototype001.diff.txt") is a
_prototype_ for SuSE Linux 12.3/AMD64/32bit. 32bit will not work
because it lacks the |__int128_t| type... see below...

Example usage:
-- snip --
$ ksh -c 'typeset -X x ; typeset -sX y ; float z ; ((
x=ast_nan(0xbeef) )) ; ((y=x, z=y)); print -- $((z))'
ast_nan(0xbeef)
-- snip --

* Notes:
- This is a prototype
- The code was only tested on SuSE 12.3/AMD64/64bit with gcc4.7.
- Surprisingly the performance overhead is barely measureable...
basically we have a few extra |isnan()| calls or macros and that's it

* ToDo:
- Put the nan payload functions into their own source file
- ABI issue: |nan("")| on some platforms only sets the highest hit in
the payload instead of 0xFFFFFFFF (e.g. set all bits). How should we
deal with it ?
- Keep the nan payload function names (*binary@(32|64|80|128)* but add
platform-specific macros to map them properly to SFDOUBLE, |long
double|, |double| and |float|). The seperation is important to keep
the #ifdef/#else/#endif hackery to a minimum and in one place
- How should we deal with the usage of |__int128_t| ? It's only
available on 64bit plaftorms with "clang" and newer "gcc" versions...
but writing a "portable" version which does the operations on a
byte/word/longword level makes the code depending on the endian-ness
of the platform. Main issue here is testing... my SPARC machine is
broken and I need some time to find money to fix it.

----

Bye,
Roland

-- 
  __ .  . __
 (o.\ \/ /.o) [email protected]
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 3992797
 (;O/ \/ \O;)
diff -r -u original/src/cmd/ksh93/data/math.tab 
build_nanpayload/src/cmd/ksh93/data/math.tab
--- src/cmd/ksh93/data/math.tab 2013-09-04 20:02:33.000000000 +0200
+++ src/cmd/ksh93/data/math.tab 2013-09-19 17:22:33.778814914 +0200
@@ -5,6 +5,7 @@
 f 1 acosh
 f 1 asin
 f 1 asinh
+f 1 ast_nan
 f 1 atan
 f 2 atan2
 f 1 atanh
diff -r -u original/src/cmd/ksh93/features/math.sh 
build_nanpayload/src/cmd/ksh93/features/math.sh
--- src/cmd/ksh93/features/math.sh      2013-09-07 06:31:37.000000000 +0200
+++ src/cmd/ksh93/features/math.sh      2013-09-19 17:14:10.339149139 +0200
@@ -25,7 +25,7 @@
 command=$0
 iffeflags="-n -v"
 iffehdrs="math.h"
-iffelibs="-lm"
+iffelibs="-last -lm"
 table=/dev/null
 
 eval $1
@@ -38,11 +38,11 @@
 
 : check ast_standards.h
 
-eval `iffe $iffeflags -F ast_standards.h -c "$cc" - tst use_ast_standards -lm 
'note{' 'math.h needs ast_standards.h' '}end' 'link{' '#include <math.h>' 
'#ifndef isgreater' '#define isgreater(a,b) 0' '#endif' 'int main() { return 
isgreater(0.0,1.0); }' '}end'`
+eval `iffe $iffeflags -F ast_standards.h -c "$cc" - tst use_ast_standards 
-last -lm 'note{' 'math.h needs ast_standards.h' '}end' 'link{' '#include 
<math.h>' '#ifndef isgreater' '#define isgreater(a,b) 0' '#endif' 'int main() { 
return isgreater(0.0,1.0); }' '}end'`
 case $_use_ast_standards in
 1)     iffeflags="$iffeflags -F ast_standards.h" ;;
 esac
-eval `iffe $iffeflags -c "$cc" - tst use_ieeefp -lm 'note{' 'ieeefp.h plays 
nice' '}end' 'link{' '#include <math.h>' '#include <ieeefp.h>' 'int main() { 
return 0; }' '}end'`
+eval `iffe $iffeflags -c "$cc" - tst use_ieeefp -last -lm 'note{' 'ieeefp.h 
plays nice' '}end' 'link{' '#include <math.h>' '#include <ieeefp.h>' 'int 
main() { return 0; }' '}end'`
 case $_use_ieeefp in
 1)     iffehdrs="$iffehdrs ieeefp.h" ;;
 esac
diff -r -u original/src/cmd/ksh93/sh/name.c 
build_nanpayload/src/cmd/ksh93/sh/name.c
--- src/cmd/ksh93/sh/name.c     2013-09-04 22:01:08.000000000 +0200
+++ src/cmd/ksh93/sh/name.c     2013-09-19 20:33:34.566356847 +0200
@@ -1747,9 +1747,9 @@
                                        if(flags&NV_LONG)
                                                ld = *((Sfdouble_t*)sp);
                                        else if(flags&NV_SHORT)
-                                               ld = *((float*)sp);
+                                               ld = 
cast_binary32_to_binary80(*((float*)sp));
                                        else
-                                               ld = *((double*)sp);
+                                               ld = 
cast_binary64_to_binary80(*((double*)sp));
                                }
                                else
                                        ld = sh_arith(shp,sp);
@@ -1765,9 +1765,9 @@
                                if(flags&NV_INTEGER)
                                {
                                        if(flags&NV_LONG)
-                                               d = (double)(*(Sfdouble_t*)sp);
+                                               d = 
cast_binary80_to_binary64((*(Sfdouble_t*)sp));
                                        else if(flags&NV_SHORT)
-                                               d = (double)(*(float*)sp);
+                                               d = 
cast_binary32_to_binary64((*(float*)sp));
                                        else
                                                d = *(double*)sp;
                                }
@@ -1783,7 +1783,7 @@
                                else if(flags&NV_APPEND)
                                        od = *(up->dp);
                                if(nv_isattr(np,NV_SHORT))
-                                       *(up->fp) = (float)od?d+od:d;
+                                       *(up->fp) = 
cast_binary64_to_binary32(od?d+od:d);
                                else
                                        *(up->dp) = od?d+od:d;
                        }
@@ -1912,6 +1912,13 @@
                        {
                                if(flags&NV_LONG)
                                        
sfprintf(shp->strbuf,"%.*Lg",LDBL_DIG,*((Sfdouble_t*)sp));
+                               else if(flags&NV_SHORT)
+                                       /*
+                                        * note: |float|2|double| promotion 
implicit,
+                                        * |cast_binary32_to_binary64() does it 
explicit
+                                        * to preserve nan payload
+                                        */
+                                       sfprintf(shp->strbuf,"%.*g",DBL_DIG, 
cast_binary32_to_binary64(*((float*)sp)));
                                else
                                        
sfprintf(shp->strbuf,"%.*g",DBL_DIG,*((double*)sp));
                        }
@@ -2920,7 +2927,7 @@
                        else
                        {
                                if(nv_isattr(np,NV_SHORT))
-                                       d = *up->fp;
+                                       d = cast_binary32_to_binary64(*up->fp);
                                else
                                        d = *up->dp;
                                if(nv_isattr (np,NV_EXPNOTE))
@@ -3038,9 +3045,9 @@
                        if(nv_isattr(np, NV_LONG))
                                r = *up->ldp;
                        else if(nv_isattr(np, NV_SHORT))
-                               r = *up->fp;
+                               r = cast_binary32_to_binary80(*up->fp);
                        else
-                                       r = *up->dp;
+                                       r = cast_binary64_to_binary80(*up->dp);
                }
                else if(nv_isattr(np, NV_UNSIGN))
                {
diff -r -u original/src/lib/libast/include/ast.h 
build_nanpayload/src/lib/libast/include/ast.h
--- src/lib/libast/include/ast.h        2013-09-10 11:01:39.000000000 +0200
+++ src/lib/libast/include/ast.h        2013-09-19 20:09:50.862074657 +0200
@@ -411,6 +411,27 @@
 extern ssize_t         utf32stowcs(wchar_t*, uint32_t*, size_t);
 extern ssize_t         wcstoutf32s(uint32_t*, wchar_t*, size_t);
 
+#if 1
+/* wrong header file, hacking here for now */
+long double ast_nanl(long double payload);
+double ast_nan(double payload);
+float ast_nanf(float payload);
+
+void set_nan_payload_binary32(float *val, unsigned int payload);
+unsigned int get_nan_payload_binary32(float x);
+void set_nan_payload_binary64(double *val, unsigned long payload);
+unsigned long get_nan_payload_binary64(double x);
+void set_nan_payload_binary80(long double *val, unsigned long payload);
+unsigned long get_nan_payload_binary80(long double x);
+float cast_binary64_to_binary32(double d);
+long double cast_binary64_to_binary80(double d);
+double cast_binary32_to_binary64(float f);
+long double cast_binary32_to_binary80(float f);
+float cast_binary80_to_binary32(long double ld);
+double cast_binary80_to_binary64(long double ld);
+
+#endif
+
 #undef                 extern
 
 /*
diff -r -u original/src/lib/libast/sfio/sfcvt.c 
build_nanpayload/src/lib/libast/sfio/sfcvt.c
--- src/lib/libast/sfio/sfcvt.c 2012-06-19 09:27:53.000000000 +0200
+++ src/lib/libast/sfio/sfcvt.c 2013-09-19 23:27:01.433165300 +0200
@@ -24,6 +24,387 @@
 #endif
 #include       "sfhdr.h"
 
+#if 1 /* nanpayload*/
+#include <stdint.h>
+#include <math.h>
+#include <limits.h>
+
+long double ast_nanl(long double payload)
+{
+       long double num=NAN;
+       set_nan_payload_binary80(&num, (unsigned long)payload);
+       return num;
+}
+double ast_nan(double payload)
+{
+       double num=NAN;
+       set_nan_payload_binary64(&num, (unsigned long)payload);
+       return num;
+}
+float ast_nanf(float payload)
+{
+       float num=NAN;
+       set_nan_payload_binary32(&num, (unsigned long)payload);
+       return num;
+}
+
+/*
+ * Notes about portablity:
+ * - The ISO C99 standards supports a portable way to write the
+ *   payload of a quiet NaN in ISO C.
+ * - The |nan()|/|nanf()|/|nanl()| functions (from <math.h>, see
+ *   section 7.12.11.2 in the ISO C99 spec) accept strings as
+ *   arguments.
+ * - |strtof()|/|strtod()|/|strtold()| functions (from <stdlib.h>,
+ *   see section 7.20.1.3) accept strings in the form
+ *   "NAN(character sequence)".
+ * - |fscanf()|+|sscanf()| follow |strtod()|
+ * - the character sequence in "NAN(character sequence)" is
+ *   interpreted in an (libc+compiler) implementation-specific
+ *   way (=not portable).
+ */
+
+void print_bits_32(uint32_t x)
+{
+       int i;
+       for (i=0 ; i < 32 ; i++)
+       {
+               /* fixme: endian! */
+               printf("%d", (x & (1<<31))?1:0);
+               x = x << 1;
+       }
+}
+void print_bits_64(uint64_t x)
+{
+       int i;
+       for (i=0 ; i < 64 ; i++)
+       {
+               /* fixme: endian! */
+               printf("%d", (x & (1LL<<63))?1:0);
+               x = x << 1;
+       }
+}
+void print_bits_128(__int128_t x)
+{
+       int i;
+       for (i=0 ; i < 128 ; i++)
+       {
+               /* fixme: endian! */
+               printf("%d", (x & (((__int128_t)1)<<127))?1:0);
+               x = x << 1;
+       }
+}
+
+void set_nan_payload_binary32(float *val, unsigned int payload)
+{
+       if (payload == 0)
+               return;
+       if (!isnanf(*val))
+               return;
+
+       volatile uint32_t *bitval_ptr = ((volatile uint32_t *)val);
+
+       const uint32_t exp_bits = log2f(FLT_MAX_EXP)+1;
+       const uint32_t frac_bits = 32-1-exp_bits;
+       const uint32_t frac_mask = powf(2, frac_bits-1)-1;
+
+       *bitval_ptr &= ~frac_mask;
+       *bitval_ptr |= (payload & frac_mask);
+}
+
+unsigned int get_nan_payload_binary32(float x)
+{
+       unsigned int payload;
+
+       if(!isnanf(x))
+               return 0;
+
+       const uint32_t exp_bits = log2(FLT_MAX_EXP)+1;
+       const uint32_t frac_bits = 32-1-exp_bits;
+       const uint32_t frac_mask = pow(2, frac_bits-1)-1;
+
+       volatile uint32_t *bitval_ptr = ((volatile uint32_t *)&x);
+
+       payload = *bitval_ptr & frac_mask;
+
+       return payload;
+}
+
+void set_nan_payload_binary64(double *val, unsigned long payload)
+{
+       if (payload == 0)
+               return;
+       if (!isnan(*val))
+               return;
+
+       volatile uint64_t *bitval_ptr = ((volatile uint64_t *)val);
+
+       const uint64_t exp_bits = log2(DBL_MAX_EXP)+1;
+       const uint64_t frac_bits = 64-1-exp_bits;
+       const uint64_t frac_mask = pow(2, frac_bits-1)-1;
+
+       *bitval_ptr &= ~frac_mask;
+       *bitval_ptr |= (payload & frac_mask);
+}
+
+unsigned long get_nan_payload_binary64(double x)
+{
+       unsigned long payload;
+
+       if(!isnan(x))
+               return 0UL;
+
+       const uint64_t exp_bits = log2(DBL_MAX_EXP)+1;
+       const uint64_t frac_bits = 64-1-exp_bits;
+       const uint64_t frac_mask = pow(2, frac_bits-1)-1;
+
+       volatile uint64_t *bitval_ptr = ((volatile uint64_t *)&x);
+
+       payload = *bitval_ptr & frac_mask;
+
+       return payload;
+}
+
+const int ldbl_bits=80/*128*/;
+
+void set_nan_payload_binary80(long double *val, unsigned long payload)
+{
+       if (payload == 0)
+               return;
+       if (!isnanl(*val))
+               return;
+
+       volatile __int128_t *bitval_ptr = ((volatile __int128_t *)val);
+
+       /* what about Intel i387 80bit |long double|? ? */
+
+       const __int128_t exp_bits = log2l(LDBL_MAX_EXP)+1;
+       const __int128_t frac_bits = ldbl_bits-1-exp_bits;
+       const __int128_t frac_mask = ((__int128_t)powl(2, frac_bits-1))-1;
+
+       *bitval_ptr &= ~frac_mask;
+       *bitval_ptr |= (payload & frac_mask);
+}
+
+unsigned long get_nan_payload_binary80(long double x)
+{
+       unsigned long payload;
+
+       if(!isnanl(x))
+               return 0;
+
+       const __int128_t exp_bits = log2l(LDBL_MAX_EXP)+1;
+       const __int128_t frac_bits = ldbl_bits-1-exp_bits;
+       const __int128_t frac_mask = ((__int128_t)powl(2, frac_bits-1))-1;
+
+       volatile __int128_t *bitval_ptr = ((volatile __int128_t *)&x);
+
+       payload = *bitval_ptr & frac_mask;
+
+       return payload;
+}
+
+float cast_binary64_to_binary32(double d)
+{
+       float f;
+
+       if (isnan(d))
+       {
+               unsigned long payload;
+
+               payload = get_nan_payload_binary64(d);
+               f = (float)d;
+
+               set_nan_payload_binary32(&f, payload);
+       }
+       else
+       {
+               f = (float)d;
+       }
+
+       return f;
+}
+
+
+long double cast_binary64_to_binary80(double d)
+{
+       long double ld;
+
+       if (isnan(d))
+       {
+               unsigned long payload;
+
+               payload = get_nan_payload_binary64(d);
+               ld = (long double)d;
+
+               set_nan_payload_binary80(&ld, payload);
+       }
+       else
+       {
+               ld = (long double)d;
+       }
+
+       return ld;
+}
+
+
+double cast_binary32_to_binary64(float f)
+{
+       double d;
+
+       if (isnanf(f))
+       {
+               unsigned long payload;
+
+               payload = get_nan_payload_binary32(f);
+               d = (double)f;
+
+               set_nan_payload_binary64(&d, payload);
+       }
+       else
+       {
+               d = (double)f;
+       }
+
+       return d;
+}
+
+
+long double cast_binary32_to_binary80(float f)
+{
+       long double ld;
+
+       if (isnanf(f))
+       {
+               unsigned long payload;
+
+               payload = get_nan_payload_binary32(f);
+               ld = (long double)f;
+
+               set_nan_payload_binary80(&ld, payload);
+       }
+       else
+       {
+               ld = (long double)f;
+       }
+
+       return ld;
+}
+
+
+float cast_binary80_to_binary32(long double ld)
+{
+       float f;
+
+       if (isnanl(ld))
+       {
+               unsigned long payload;
+
+               payload = get_nan_payload_binary80(ld);
+               f = (float)ld;
+
+               set_nan_payload_binary32(&f, payload);
+       }
+       else
+       {
+               f = (float)ld;
+       }
+
+       return f;
+}
+
+
+double cast_binary80_to_binary64(long double ld)
+{
+       double d;
+
+       if (isnanl(ld))
+       {
+               unsigned long payload;
+
+               payload = get_nan_payload_binary80(ld);
+               d = (double)ld;
+
+               set_nan_payload_binary64(&d, payload);
+       }
+       else
+       {
+               d = (double)ld;
+       }
+
+       return d;
+}
+
+#if 0
+int main(int ac, char *av[])
+{
+       volatile float val=NAN;
+
+       long i;
+
+       uint32_t *xp=(uint32_t *)&val;
+
+       printf("orig:\t" ); print_bits_32(*xp); printf("\tval=%f\n", val);
+
+       const uint32_t exp_bits = log2(FLT_MAX_EXP)+1;
+       const uint32_t frac_bits = 32-1-exp_bits;
+       const uint32_t frac_mask = pow(2, frac_bits-1)-1;
+
+       printf("exp_bits=%d, frac_bits=%d, frac_mask=%lx\n", exp_bits, 
frac_bits, (unsigned long)frac_mask);
+
+       printf("frcmsk:\t" ); print_bits_32(frac_mask); printf("\n");
+
+       *xp |= 0x01;
+       printf("0x01:\t" ); print_bits_32(*xp); printf("\tval=%f\n", val);
+
+       for (i=0 ; i <= frac_mask ; i++)
+       {
+               volatile uint32_t *bitval_ptr = ((volatile uint32_t *)&val);
+
+               val = NAN;
+               *bitval_ptr &= ~frac_mask;
+               *bitval_ptr |= (i & frac_mask);
+               if (!isnan(val))
+                       printf("%f not a nan for %ld\n", val, (long)i);
+               if (isinf(val))
+                       printf("%f is a inf for %ld\n", val, (long)i);
+       }
+
+       {
+               float fval;
+               fval = -NAN;
+               set_nan_payload_binary32(&fval, 667);
+               printf("flt: val with -NAN667=%f\n", fval);
+               printf("flt: payload of -NAN667=%d\n", 
(int)get_nan_payload_binary32(fval));
+       }
+
+       {
+               double dval;
+               dval = -NAN;
+               set_nan_payload_binary64(&dval, 667);
+               printf("dbl: val with -NAN667=%f\n", dval);
+               printf("dbl: payload of -NAN667=%lu\n", (unsigned 
long)get_nan_payload_binary64(dval));
+               printf("dbl: payload of sys_cast float(-NAN667)=%lu\n", 
(unsigned long)get_nan_payload_binary32((float)dval));
+               printf("dbl: payload of own_cast float(-NAN667)=%lu\n", 
(unsigned long)get_nan_payload_binary32(cast_binary64_to_binary32(dval)));
+       }
+
+       {
+               long double ldval;
+               ldval = -NAN;
+               set_nan_payload_binary80(&ldval, 667);
+               printf("ldbl: val with -NAN667=%Lf\n", ldval);
+               printf("ldbl: payload of -NAN667=%lu\n", (unsigned 
long)get_nan_payload_binary80(ldval));
+               printf("ldbl: payload of sys_cast double(-NAN667)=%lu\n", 
(unsigned long)get_nan_payload_binary64((double)ldval));
+               printf("ldbl: payload of own_cast double(-NAN667)=%lu\n", 
(unsigned long)get_nan_payload_binary64(cast_binary80_to_binary64(ldval)));
+       }
+
+       return EXIT_SUCCESS;
+}
+
+#endif
+
+#endif /* nanpayload */
+
 /*     Convert a floating point value to ASCII.
 **
 **     Written by Kiem-Phong Vo and Glenn Fowler (SFFMT_AFORMAT)
@@ -118,8 +499,8 @@
        int                     x;
        _ast_flt_unsigned_max_t m;
 
-       static char             lx[] = "0123456789abcdef";
-       static char             ux[] = "0123456789ABCDEF";
+       static const char       lx[] = "0123456789abcdef";
+       static const char       ux[] = "0123456789ABCDEF";
 
        *sign = *decpt = 0;
 
@@ -129,13 +510,26 @@
 
                if(isnanl(f))
                {       
+                       unsigned long payload;
 #if _lib_signbit
                        if (signbit(f))
 #else
                        if (f < 0)
 #endif
                                *sign = 1;
-                       return SF_NAN;
+#if 1
+                       /* grrr... on some platforms the default |NAN| sets 
only one bit instead of using 0xFFFFFFFF */
+                       payload = get_nan_payload_binary80(f);
+                       if ((payload != 0) && (payload != 
get_nan_payload_binary80(nanl(""))))
+#else
+                       if (payload = get_nan_payload_binary80(f))
+#endif
+                       {
+                               snprintf(buf, size, "ast_nan(0x%lx)", (unsigned 
long)payload);
+                               return buf; 
+                       }
+                       else
+                               return SF_NAN;
                }
 #if _lib_isinf
                if (n = isinf(f))
@@ -172,7 +566,7 @@
                case FP_INFINITE:
                        return SF_INF;
                case FP_NAN:
-                       return SF_NAN;
+                       return SF_NAN; /* isn't this redundant since we handle 
nan already above ? */
                case FP_ZERO:
                        return SF_ZERO;
                }
@@ -306,14 +700,27 @@
        {       double  f = *(double*)vp;
 
                if(isnan(f))
-               {       
+               {
+                       unsigned long payload;
 #if _lib_signbit
                        if (signbit(f))
 #else
                        if (f < 0)
 #endif
                                *sign = 1;
-                       return SF_NAN;
+#if 1
+                       /* grrr... on some platforms the default |NAN| sets 
only one bit instead of using 0xFFFFFFFF */
+                       payload = get_nan_payload_binary64(f);
+                       if ((payload != 0) && (payload != 
get_nan_payload_binary64(nan(""))))
+#else
+                       if (payload = get_nan_payload_binary64(f))
+#endif
+                       {
+                               snprintf(buf, size, "ast_nan(0x%lx)", (unsigned 
long)payload);
+                               return buf; 
+                       }
+                       else
+                               return SF_NAN;
                }
 #if _lib_isinf
                if (n = isinf(f))
@@ -530,3 +937,4 @@
        ep = sp + 1;
        goto done;
 }
+
_______________________________________________
ast-developers mailing list
[email protected]
http://lists.research.att.com/mailman/listinfo/ast-developers

Reply via email to