X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/9385eb3d10ebe5eb398c52040ec3dbfba9b0cdcf..2acb89982f71719aec26ca16705bd2c0400a9550:/gdtoa/FreeBSD/gdtoaimp.h diff --git a/gdtoa/FreeBSD/gdtoaimp.h b/gdtoa/FreeBSD/gdtoaimp.h index dd398e4..b967e81 100644 --- a/gdtoa/FreeBSD/gdtoaimp.h +++ b/gdtoa/FreeBSD/gdtoaimp.h @@ -26,8 +26,6 @@ THIS SOFTWARE. ****************************************************************/ -/* $FreeBSD: src/contrib/gdtoa/gdtoaimp.h,v 1.5 2003/04/09 06:04:35 das Exp $ */ - /* This is a variation on dtoa.c that converts arbitary binary floating-point formats to and from decimal notation. It uses double-precision arithmetic internally, so there are still @@ -35,13 +33,8 @@ THIS SOFTWARE. double-precision arithmetic (any of IEEE, VAX D_floating, or IBM mainframe arithmetic). - Please send bug reports to - David M. Gay - Bell Laboratories, Room 2C-463 - 600 Mountain Avenue - Murray Hill, NJ 07974-0636 - U.S.A. - dmg@bell-labs.com + Please send bug reports to David M. Gay (dmg at acm dot org, + with " at " changed at "@" and " dot " changed to "."). */ /* On a machine with IEEE extended-precision registers, it is @@ -63,7 +56,7 @@ THIS SOFTWARE. * biased rounding (add half and chop). * * Inspired loosely by William D. Clinger's paper "How to Read Floating - * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * @@ -120,7 +113,12 @@ THIS SOFTWARE. * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) * if memory is available and otherwise does something you deem * appropriate. If MALLOC is undefined, malloc will be invoked - * directly -- and assumed always to succeed. + * directly -- and assumed always to succeed. Similarly, if you + * want something other than the system's free() to be called to + * recycle memory acquired from MALLOC, #define FREE to be the + * name of the alternate routine. (FREE or free is only called in + * pathological cases, e.g., in a gdtoa call after a gdtoa return in + * mode 3 with thousands of digits requested.) * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making * memory allocations from a private pool of memory when possible. * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, @@ -133,20 +131,22 @@ THIS SOFTWARE. * conversions of IEEE doubles in single-threaded executions with * 8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with * 4-byte pointers, PRIVATE_MEM >= 7112 appears adequate. - * #define INFNAN_CHECK on IEEE systems to cause strtod to check for - * Infinity and NaN (case insensitively). On some systems (e.g., - * some HP systems), it may be necessary to #define NAN_WORD0 - * appropriately -- to the most significant word of a quiet NaN. - * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK + * #defined automatically on IEEE systems. On such systems, + * when INFNAN_CHECK is #defined, strtod checks + * for Infinity and NaN (case insensitively). * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, * strtodg also accepts (case insensitively) strings of the form - * NaN(x), where x is a string of hexadecimal digits and spaces; - * if there is only one string of hexadecimal digits, it is taken - * for the fraction bits of the resulting NaN; if there are two or - * more strings of hexadecimal digits, each string is assigned - * to the next available sequence of 32-bit words of fractions - * bits (starting with the most significant), right-aligned in - * each sequence. + * NaN(x), where x is a string of hexadecimal digits (optionally + * preceded by 0x or 0X) and spaces; if there is only one string + * of hexadecimal digits, it is taken for the fraction bits of the + * resulting NaN; if there are two or more strings of hexadecimal + * digits, each string is assigned to the next available sequence + * of 32-bit words of fractions bits (starting with the most + * significant), right-aligned in each sequence. + * Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)" + * is consumed even when ... has the wrong form (in which case the + * "(...)" is consumed but ignored). * #define MULTIPLE_THREADS if the system offers preemptively scheduled * multiple threads. In this case, you must provide (or suitably * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed @@ -158,7 +158,7 @@ THIS SOFTWARE. * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. * #define IMPRECISE_INEXACT if you do not care about the setting of * the STRTOG_Inexact bits in the special case of doing IEEE double - * precision conversions (which could also be done by the strtog in + * precision conversions (which could also be done by the strtod in * dtoa.c). * #define NO_HEX_FP to disable recognition of C9x's hexadecimal * floating-point constants. @@ -167,17 +167,101 @@ THIS SOFTWARE. * #define NO_STRING_H to use private versions of memcpy. * On some K&R systems, it may also be necessary to * #define DECLARE_SIZE_T in this case. - * #define YES_ALIAS to permit aliasing certain double values with - * arrays of ULongs. This leads to slightly better code with - * some compilers and was always used prior to 19990916, but it - * is not strictly legal and can cause trouble with aggressively - * optimizing compilers (e.g., gcc 2.95.1 under -O2). * #define USE_LOCALE to use the current locale's decimal_point value. */ #ifndef GDTOAIMP_H_INCLUDED #define GDTOAIMP_H_INCLUDED +/* + * Paranoia: Protect exported symbols, including ones in files we don't + * compile right now. The standard strtof and strtod survive. + */ +#define dtoa __dtoa +#define gdtoa __gdtoa +#define freedtoa __freedtoa +#define strtodg __strtodg +#define g_ddfmt __g_ddfmt +#define g_dfmt __g_dfmt +#define g_ffmt __g_ffmt +#define g_Qfmt __g_Qfmt +#define g_xfmt __g_xfmt +#define g_xLfmt __g_xLfmt +#define strtoId __strtoId +#define strtoIdd __strtoIdd +#define strtoIf __strtoIf +#define strtoIQ __strtoIQ +#define strtoIx __strtoIx +#define strtoIxL __strtoIxL +#define strtord __strtord +#define strtordd __strtordd +#define strtorf __strtorf +#define strtorQ __strtorQ +#define strtorx __strtorx +#define strtorxL __strtorxL +#define strtodI __strtodI +#define strtopd __strtopd +#define strtopdd __strtopdd +#define strtopf __strtopf +#define strtopQ __strtopQ +#define strtopx __strtopx +#define strtopxL __strtopxL + +/* Protect gdtoa-internal symbols */ +#define Balloc __Balloc_D2A +#define Bfree __Bfree_D2A +#define ULtoQ __ULtoQ_D2A +#define ULtof __ULtof_D2A +#define ULtod __ULtod_D2A +#define ULtodd __ULtodd_D2A +#define ULtox __ULtox_D2A +#define ULtoxL __ULtoxL_D2A +#define any_on __any_on_D2A +#define b2d __b2d_D2A +#define bigtens __bigtens_D2A +#define cmp __cmp_D2A +#define copybits __copybits_D2A +#define d2b __d2b_D2A +#define decrement __decrement_D2A +#define diff __diff_D2A +#define dtoa_result __dtoa_result_D2A +#define g__fmt __g__fmt_D2A +#define gethex __gethex_D2A +#define hexdig __hexdig_D2A +#define hexdig_init_D2A __hexdig_init_D2A +#define hexnan __hexnan_D2A +#define hi0bits __hi0bits_D2A +#define hi0bits_D2A __hi0bits_D2A +#define i2b __i2b_D2A +#define increment __increment_D2A +#define lo0bits __lo0bits_D2A +#define lshift __lshift_D2A +#define match __match_D2A +#define mult __mult_D2A +#define multadd __multadd_D2A +#define nrv_alloc __nrv_alloc_D2A +#define pow5mult __pow5mult_D2A +#define quorem __quorem_D2A +#define ratio __ratio_D2A +#define rshift __rshift_D2A +#define rv_alloc __rv_alloc_D2A +#define s2b __s2b_D2A +#define set_ones __set_ones_D2A +#define strcp __strcp_D2A +#define strcp_D2A __strcp_D2A +#define strtoIg __strtoIg_D2A +#define sum __sum_D2A +#define tens __tens_D2A +#define tinytens __tinytens_D2A +#define tinytens __tinytens_D2A +#define trailz __trailz_D2A +#define ulp __ulp_D2A + +#include #include "gdtoa.h" +#include "gd_qnan.h" +#ifdef Honor_FLT_ROUNDS +#include +#endif #ifdef DEBUG #include "stdio.h" @@ -204,6 +288,7 @@ extern Char *MALLOC ANSI((size_t)); #define INFNAN_CHECK #define USE_LOCALE +#define NO_LOCALE_CACHE #undef IEEE_Arith #undef Avoid_Underflow @@ -277,25 +362,14 @@ Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. typedef union { double d; ULong L[2]; } U; -#ifdef YES_ALIAS -#define dval(x) x #ifdef IEEE_8087 -#define word0(x) ((ULong *)&x)[1] -#define word1(x) ((ULong *)&x)[0] +#define word0(x) (x)->L[1] +#define word1(x) (x)->L[0] #else -#define word0(x) ((ULong *)&x)[0] -#define word1(x) ((ULong *)&x)[1] +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] #endif -#else /* !YES_ALIAS */ -#ifdef IEEE_8087 -#define word0(x) ((U*)&x)->L[1] -#define word1(x) ((U*)&x)->L[0] -#else -#define word0(x) ((U*)&x)->L[0] -#define word1(x) ((U*)&x)->L[1] -#endif -#define dval(x) ((U*)&x)->d -#endif /* YES_ALIAS */ +#define dval(x) (x)->d /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is @@ -466,16 +540,14 @@ extern double rnd_prod(double, double), rnd_quot(double, double); #define MULTIPLE_THREADS extern spinlock_t __gdtoa_locks[2]; -#define ACQUIRE_DTOA_LOCK(n) do { \ - if (__isthreaded) \ - _SPINLOCK(&__gdtoa_locks[n]); \ +#define ACQUIRE_DTOA_LOCK(n) do { \ + if (__isthreaded) _SPINLOCK(&__gdtoa_locks[n]); \ } while(0) -#define FREE_DTOA_LOCK(n) do { \ - if (__isthreaded) \ - _SPINUNLOCK(&__gdtoa_locks[n]); \ +#define FREE_DTOA_LOCK(n) do { \ + if (__isthreaded) _SPINUNLOCK(&__gdtoa_locks[n]); \ } while(0) -#define Kmax 15 +#define Kmax 9 struct Bigint { @@ -496,92 +568,9 @@ extern void memcpy_D2A ANSI((void*, const void*, size_t)); #define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int)) #endif /* NO_STRING_H */ -/* - * Paranoia: Protect exported symbols, including ones in files we don't - * compile right now. The standard strtof and strtod survive. - */ -#define dtoa __dtoa -#define gdtoa __gdtoa -#define freedtoa __freedtoa -#define strtodg __strtodg -#define g_ddfmt __g_ddfmt -#define g_dfmt __g_dfmt -#define g_ffmt __g_ffmt -#define g_Qfmt __g_Qfmt -#define g_xfmt __g_xfmt -#define g_xLfmt __g_xLfmt -#define strtoId __strtoId -#define strtoIdd __strtoIdd -#define strtoIf __strtoIf -#define strtoIQ __strtoIQ -#define strtoIx __strtoIx -#define strtoIxL __strtoIxL -#define strtord __strtord -#define strtordd __strtordd -#define strtorf __strtorf -#define strtorQ __strtorQ -#define strtorx __strtorx -#define strtorxL __strtorxL -#define strtodI __strtodI -#define strtopd __strtopd -#define strtopdd __strtopdd -#define strtopf __strtopf -#define strtopQ __strtopQ -#define strtopx __strtopx -#define strtopxL __strtopxL - -/* Protect gdtoa-internal symbols */ -#define Balloc __Balloc_D2A -#define Bfree __Bfree_D2A -#define ULtoQ __ULtoQ_D2A -#define ULtof __ULtof_D2A -#define ULtod __ULtod_D2A -#define ULtodd __ULtodd_D2A -#define ULtox __ULtox_D2A -#define ULtoxL __ULtoxL_D2A -#define any_on __any_on_D2A -#define b2d __b2d_D2A -#define bigtens __bigtens_D2A -#define cmp __cmp_D2A -#define copybits __copybits_D2A -#define d2b __d2b_D2A -#define decrement __decrement_D2A -#define diff __diff_D2A -#define dtoa_result __dtoa_result_D2A -#define g__fmt __g__fmt_D2A -#define gethex __gethex_D2A -#define hexdig __hexdig_D2A -#define hexdig_init_D2A __hexdig_init_D2A -#define hexnan __hexnan_D2A -#define hi0bits __hi0bits_D2A -#define i2b __i2b_D2A -#define increment __increment_D2A -#define lo0bits __lo0bits_D2A -#define lshift __lshift_D2A -#define match __match_D2A -#define mult __mult_D2A -#define multadd __multadd_D2A -#define nrv_alloc __nrv_alloc_D2A -#define pow5mult __pow5mult_D2A -#define quorem __quorem_D2A -#define ratio __ratio_D2A -#define rshift __rshift_D2A -#define rv_alloc __rv_alloc_D2A -#define s2b __s2b_D2A -#define set_ones __set_ones_D2A -#define strcp __strcp_D2A -#define strcp_D2A __strcp_D2A -#define strtoIg __strtoIg_D2A -#define sum __sum_D2A -#define tens __tens_D2A -#define tinytens __tinytens_D2A -#define tinytens __tinytens_D2A -#define trailz __trailz_D2A -#define ulp __ulp_D2A - extern char *dtoa_result; extern CONST double bigtens[], tens[], tinytens[]; - extern unsigned char hexdig[]; + extern CONST unsigned char hexdig[]; extern Bigint *Balloc ANSI((int)); extern void Bfree ANSI((Bigint*)); @@ -596,18 +585,15 @@ extern void memcpy_D2A ANSI((void*, const void*, size_t)); extern int cmp ANSI((Bigint*, Bigint*)); extern void copybits ANSI((ULong*, int, Bigint*)); extern Bigint *d2b ANSI((double, int*, int*)); - extern int decrement ANSI((Bigint*)); + extern void decrement ANSI((Bigint*)); extern Bigint *diff ANSI((Bigint*, Bigint*)); extern char *dtoa ANSI((double d, int mode, int ndigits, int *decpt, int *sign, char **rve)); - extern void freedtoa ANSI((char*)); - extern char *gdtoa ANSI((FPI *fpi, int be, ULong *bits, int *kindp, - int mode, int ndigits, int *decpt, char **rve)); - extern char *g__fmt ANSI((char*, char*, char*, int, ULong)); - extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int)); + extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t)); + extern int gethex ANSI((CONST char**, CONST FPI*, Long*, Bigint**, int, locale_t)); extern void hexdig_init_D2A(Void); - extern int hexnan ANSI((CONST char**, FPI*, ULong*)); - extern int hi0bits ANSI((ULong)); + extern int hexnan ANSI((CONST char**, CONST FPI*, ULong*)); + extern int hi0bits_D2A ANSI((ULong)); extern Bigint *i2b ANSI((int)); extern Bigint *increment ANSI((Bigint*)); extern int lo0bits ANSI((ULong*)); @@ -621,62 +607,55 @@ extern void memcpy_D2A ANSI((void*, const void*, size_t)); extern double ratio ANSI((Bigint*, Bigint*)); extern void rshift ANSI((Bigint*, int)); extern char *rv_alloc ANSI((int)); - extern Bigint *s2b ANSI((CONST char*, int, int, ULong)); + extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int)); extern Bigint *set_ones ANSI((Bigint*, int)); extern char *strcp ANSI((char*, const char*)); - extern int strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*)); - - extern int strtoId ANSI((CONST char *, char **, double *, double *)); - extern int strtoIdd ANSI((CONST char *, char **, double *, double *)); - extern int strtoIf ANSI((CONST char *, char **, float *, float *)); extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*)); - extern int strtoIQ ANSI((CONST char *, char **, void *, void *)); - extern int strtoIx ANSI((CONST char *, char **, void *, void *)); - extern int strtoIxL ANSI((CONST char *, char **, void *, void *)); extern double strtod ANSI((const char *s00, char **se)); - extern int strtopQ ANSI((CONST char *, char **, Void *)); - extern int strtopf ANSI((CONST char *, char **, float *)); - extern int strtopd ANSI((CONST char *, char **, double *)); - extern int strtopdd ANSI((CONST char *, char **, double *)); - extern int strtopx ANSI((CONST char *, char **, Void *)); - extern int strtopxL ANSI((CONST char *, char **, Void *)); - extern int strtord ANSI((CONST char *, char **, int, double *)); - extern int strtordd ANSI((CONST char *, char **, int, double *)); - extern int strtorf ANSI((CONST char *, char **, int, float *)); - extern int strtorQ ANSI((CONST char *, char **, int, void *)); - extern int strtorx ANSI((CONST char *, char **, int, void *)); - extern int strtorxL ANSI((CONST char *, char **, int, void *)); + extern double strtod_l ANSI((const char *s00, char **se, locale_t)); extern Bigint *sum ANSI((Bigint*, Bigint*)); extern int trailz ANSI((Bigint*)); - extern double ulp ANSI((double)); + extern double ulp ANSI((U*)); #ifdef __cplusplus } #endif - - +/* + * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c. Prior to + * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0, + * respectively), but now are determined by compiling and running + * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1. + * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=... + * and -DNAN_WORD1=... values if necessary. This should still work. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + */ #ifdef IEEE_Arith +#ifndef NO_INFNAN_CHECK +#undef INFNAN_CHECK +#define INFNAN_CHECK +#endif #ifdef IEEE_MC68k #define _0 0 #define _1 1 +#ifndef NAN_WORD0 +#define NAN_WORD0 d_QNAN0 +#endif +#ifndef NAN_WORD1 +#define NAN_WORD1 d_QNAN1 +#endif #else #define _0 1 #define _1 0 -#endif -#else -#undef INFNAN_CHECK -#endif - -#ifdef INFNAN_CHECK - #ifndef NAN_WORD0 -#define NAN_WORD0 0x7ff80000 +#define NAN_WORD0 d_QNAN1 #endif - #ifndef NAN_WORD1 -#define NAN_WORD1 0 +#define NAN_WORD1 d_QNAN0 +#endif +#endif +#else +#undef INFNAN_CHECK #endif -#endif /* INFNAN_CHECK */ #undef SI #ifdef Sudden_Underflow @@ -685,4 +664,78 @@ extern void memcpy_D2A ANSI((void*, const void*, size_t)); #define SI 0 #endif +/* + * For very large strings, strtod and family might exhaust memory in tight + * memory conditions (especially in 32-bits). Such large strings could also + * tie up a CPU for minutes at a time. Either can be considered a denial-of- + * service vunerability. + * + * To fix, we limit the string size to the maximum we need to calculate the + * rounding point correctly. The longest string corresponding to the exact + * value of a floating point number occuring at 1.f...f p^-n, where n is + * the (absolute value of the) smallest exponent for a normalize number. + * + * To calculate this number of decimal digits, we use the formula: + * + * (n + m) - int(n * log10(2)) + 3 + * + * where m is the number of bits in the f...f fraction. This is the number + * of decimal digits for the least significant bit minus the number of leading + * zeros for the most significant bit (the '1'), plus a few to compensate for + * an extra digits due to the full 1.f...f value, an extra digit for the + * mid-way point for rounding and an extra guard digit. + * + * Using the approximation log10(2) ~ 1233 / (2^12), converting to the fpi.emin + * and fpi.nbits values, we get: + * + * -fpi.emin -((1233 * (-fpi.nbits - fpi.emin)) >> 12) + 3 + * + * Finally, we add an extra digit, either '1' or '0', to represent whether + * to-be-truncated digits contain a non-zero digit, or are all zeros, + * respectively. + * + * The truncated string is allocated on the heap, so code using + * TRUNCATE_DIGITS() will need to free that space when no longer needed. + * Pass a char * as the second argument, initialized to NULL; if its value + * becomes non-NULL, memory was allocated. + */ +#define LOG2NUM 1233 +#define LOG2DENOMSHIFT 12 +#define TRUNCATEDIGITS(_nbits, _emin) (-(_emin) - ((LOG2NUM * (-(_nbits) - (_emin))) >> LOG2DENOMSHIFT) + 3) + +#define TRUNCATE_DIGITS(_s0, _temp, _nd, _nd0, _nf, _nbits, _emin, _dplen) \ +{ \ + int _maxdigits = TRUNCATEDIGITS((_nbits), (_emin)); \ + if ((_nd) > _maxdigits && \ + ((_temp) = MALLOC(_maxdigits + (_dplen) + 2)) != NULL) { \ + char *_tp = (_temp) + _maxdigits; \ + if ((_nd0) >= _maxdigits) { \ + memcpy((_temp), (_s0), _maxdigits); \ + if ((_nd) > (_nd0)) *_tp++ = '1'; \ + else { \ + const char *_q = (_s0) + _maxdigits; \ + int _n = (_nd0) - _maxdigits; \ + for(; _n > 0 && *_q == '0'; _n--, _q++) {} \ + *_tp++ = _n > 0 ? '1' : '0'; \ + } \ + (_nf) = -((_nd0) - (_maxdigits + 1)); \ + (_nd0) = _maxdigits + 1; \ + } \ + else if ((_nd0) == 0) { \ + memcpy((_temp), (_s0), _maxdigits); \ + *_tp++ = '1'; \ + (_nf) -= ((_nd) - (_maxdigits + 1)); \ + } \ + else { \ + memcpy((_temp), (_s0), _maxdigits + (_dplen)); \ + _tp += (_dplen); \ + *_tp++ = '1'; \ + (_nf) = (_maxdigits + 1) - (_nd0); \ + } \ + *_tp = 0; \ + (_nd) = _maxdigits + 1; \ + (_s0) = (_temp); \ + } \ + } + #endif /* GDTOAIMP_H_INCLUDED */