****************************************************************/
-/* $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
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
* 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:
*
* #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,
* 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
* 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.
* #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 <xlocale.h>
#include "gdtoa.h"
+#include "gd_qnan.h"
+#ifdef Honor_FLT_ROUNDS
+#include <fenv.h>
+#endif
#ifdef DEBUG
#include "stdio.h"
#define INFNAN_CHECK
#define USE_LOCALE
+#define NO_LOCALE_CACHE
#undef IEEE_Arith
#undef Avoid_Underflow
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
#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 {
#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*));
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*));
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
#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 */