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