1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-14 10:09:48 +00:00

Since nan() is supposed to work the same as strtod("nan(...)", NULL),

my original implementation made both use the same code. Unfortunately,
this meant libm depended on a vendor header at compile time and previously-
unexposed vendor bits in libc at runtime.

Hence, I just wrote my own version of the relevant vendor routine. As it
turns out, mine has a factor of 8 fewer of lines of code, and is a bit more
readable anyway. The strtod() and *scanf() routines still use vendor code.

Reviewed by:	bde
This commit is contained in:
David Schultz 2007-12-18 23:46:32 +00:00
parent b96ebbf2e8
commit 7cd4a83267
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=174759
8 changed files with 85 additions and 50 deletions

View File

@ -71,7 +71,4 @@ FBSDprivate_1.0 {
_end;
__sys_vfork;
_vfork;
/* used in libm */
__ULtox_D2A;
};

View File

@ -68,7 +68,4 @@ FBSDprivate_1.0 {
_brk;
.curbrk;
.minbrk;
/* used in libm */
__ULtox_D2A;
};

View File

@ -69,7 +69,4 @@ FBSDprivate_1.0 {
minbrk;
.cerror;
curbrk;
/* used in libm */
__ULtox_D2A;
};

View File

@ -96,7 +96,4 @@ FBSDprivate_1.0 {
/* used in src/lib/csu/sparc64/crt1.c */
__sparc_utrap_setup;
/* used in libm */
__ULtoQ_D2A;
};

View File

@ -29,19 +29,18 @@
#include <math.h>
#include "fpmath.h"
#include "../../../contrib/gdtoa/gdtoaimp.h"
#include "../src/math_private.h"
long double
nanl(const char *s)
{
static FPI fpi = { 113, -16494, 16271, 1, SI };
union {
union IEEEl2bits ieee;
uint32_t bits[4];
} u;
union IEEEl2bits result;
ULong bits[2];
int k;
s--;
k = hexnan(&s, &fpi, bits);
ULtoQ((UShort *)&result.e, bits, 16272, k);
return (result.e);
_scan_nan(u.bits, 4, s);
u.ieee.bits.exp = 0x7fff;
u.ieee.bits.manh |= 1 << 47; /* make it a quiet NaN */
return (u.ieee.e);
}

View File

@ -29,19 +29,18 @@
#include <math.h>
#include "fpmath.h"
#include "../../../contrib/gdtoa/gdtoaimp.h"
#include "../src/math_private.h"
long double
nanl(const char *s)
{
static FPI fpi = { 64, -16445, 16320, 1, SI };
union {
union IEEEl2bits ieee;
uint32_t bits[3];
} u;
union IEEEl2bits result;
ULong bits[2];
int k;
s--;
k = hexnan(&s, &fpi, bits);
ULtox((UShort *)&result.e, bits, 16321, k);
return (result.e);
_scan_nan(u.bits, 3, s);
u.ieee.bits.exp = 0x7fff;
u.ieee.bits.manh |= 0xc0000000; /* make it a quiet NaN */
return (u.ieee.e);
}

View File

@ -154,6 +154,11 @@ do { \
(d) = sf_u.value; \
} while (0)
/*
* Common routine to process the arguments to nan(), nanf(), and nanl().
*/
void _scan_nan(uint32_t *__words, int __num_words, const char *__s);
#ifdef _COMPLEX_H
/*
* Inline functions that can be used to construct complex values.

View File

@ -26,39 +26,83 @@
* $FreeBSD$
*/
#include <sys/endian.h>
#include <ctype.h>
#include <float.h>
#include <math.h>
#include <stdint.h>
#include <strings.h>
#include "../../../contrib/gdtoa/gdtoaimp.h"
#include "math_private.h"
/*
* Scan a string of hexadecimal digits (the format nan(3) expects) and
* make a bit array (using the local endianness). We stop when we
* encounter an invalid character, NUL, etc. If we overflow, we do
* the same as gcc's __builtin_nan(), namely, discard the high order bits.
*
* The format this routine accepts needs to be compatible with what is used
* in contrib/gdtoa/hexnan.c (for strtod/scanf) and what is used in
* __builtin_nan(). In fact, we're only 100% compatible for strings we
* consider valid, so we might be violating the C standard. But it's
* impossible to use nan(3) portably anyway, so this seems good enough.
*/
void
_scan_nan(uint32_t *words, int num_words, const char *s)
{
int si; /* index into s */
int bitpos; /* index into words (in bits) */
bzero(words, num_words * sizeof(uint32_t));
/* Allow a leading '0x'. (It's expected, but redundant.) */
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
s += 2;
/* Scan forwards in the string, looking for the end of the sequence. */
for (si = 0; isxdigit(s[si]); si++)
;
/* Scan backwards, filling in the bits in words[] as we go. */
#if _BYTE_ORDER == _LITTLE_ENDIAN
for (bitpos = 0; bitpos < 32 * num_words; bitpos += 4) {
#else
for (bitpos = 32 * num_words - 4; bitpos >= 0; bitpos -= 4) {
#endif
if (--si < 0)
break;
words[bitpos / 32] |= digittoint(s[si]) << (bitpos % 32);
}
}
double
nan(const char *s)
{
static FPI fpi = { 52, -1074, 971, 1, SI };
union {
double d;
uint32_t bits[2];
} u;
double result;
ULong bits[2];
s--;
hexnan(&s, &fpi, bits);
SET_HIGH_WORD(result, 0x7ff80000 | bits[1]);
SET_LOW_WORD(result, bits[0]);
return (result);
_scan_nan(u.bits, 2, s);
#if _BYTE_ORDER == _LITTLE_ENDIAN
u.bits[1] |= 0x7ff80000;
#else
u.bits[0] |= 0x7ff80000;
#endif
return (u.d);
}
float
nanf(const char *s)
{
static FPI fpi = { 24, -149, 104, 1, SI };
union {
float f;
uint32_t bits[1];
} u;
float result;
ULong bits[1];
s--;
hexnan(&s, &fpi, bits);
SET_FLOAT_WORD(result, 0x7fc00000 | bits[0]);
return (result);
_scan_nan(u.bits, 1, s);
u.bits[0] |= 0x7fc00000;
return (u.f);
}
#if (LDBL_MANT_DIG == 53)