X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fstrtod.c;h=76840194276682ceee8553fff3bd4860f3e9d548;hb=053d1dfd787b5e0151d3d370889a1c06bab72670;hp=e6ae96bf94baab628cdda2f119fca4d3b6af3b41;hpb=6110fc90713ce59ff0996fcd3520e09a96575820;p=mono.git diff --git a/mono/utils/strtod.c b/mono/utils/strtod.c index e6ae96bf94b..76840194276 100644 --- a/mono/utils/strtod.c +++ b/mono/utils/strtod.c @@ -1,64 +1,8 @@ -/* - * This strtod has been modified to not use values from the locale, - * but to hardcode the `.' as the separator. Our class libraries will - * make sure that only the dot is passed. - * - * This is so we do not call `setlocale' from our runtime before doing - * a strtod, because this could have unwanted effects in code that is - * co-hosted with the Mono runtime - * - * The entry point has been renamed `bsd_strtod'. - * - * Taken from the FreeBSD distribution. - */ -#include - -#include "strtod.h" - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/lib/libc/stdlib/strtod.c,v 1.3.8.3 2002/04/17 12:01:21 ache Exp $ - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strtod.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ - /**************************************************************** * * The author of this software is David M. Gay. * - * Copyright (c) 1991 by AT&T. + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice @@ -67,19 +11,34 @@ static char sccsid[] = "@(#)strtod.c 8.1 (Berkeley) 6/4/93"; * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ - -/* Please send bug reports to - David M. Gay - AT&T Bell Laboratories, Room 2C-463 - 600 Mountain Avenue - Murray Hill, NJ 07974-2070 - U.S.A. - dmg@research.att.com or research!dmg +#include "strtod.h" +#include +#define freedtoa __freedtoa +#define dtoa __dtoa + +G_LOCK_DEFINE_STATIC(str_mutex0); +G_LOCK_DEFINE_STATIC(str_mutex1); +#define MULTIPLE_THREADS 1 +#define ACQUIRE_DTOA_LOCK(n) G_LOCK (str_mutex##n) +#define FREE_DTOA_LOCK(n) G_UNLOCK (str_mutex##n) + +/* 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 + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. */ /* strtod for IEEE-, VAX-, and IBM-arithmetic machines. @@ -117,48 +76,121 @@ static char sccsid[] = "@(#)strtod.c 8.1 (Berkeley) 6/4/93"; * significant byte has the lowest address. * #define IEEE_MC68k for IEEE-arithmetic machines where the most * significant byte has the lowest address. - * #define Sudden_Underflow for IEEE-format machines without gradual - * underflow (i.e., that flush to zero on underflow). + * #define Long int on machines with 32-bit ints and 64-bit longs. * #define IBM for IBM mainframe-style floating-point arithmetic. - * #define VAX for VAX-style floating-point arithmetic. - * #define Unsigned_Shifts if >> does treats its left operand as unsigned. + * #define VAX for VAX-style floating-point arithmetic (D_floating). * #define No_leftright to omit left-right logic in fast floating-point * computation of dtoa. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines * that use extended-precision instructions to compute rounded * products and quotients) with IBM. * #define ROUND_BIASED for IEEE-format with biased rounding. * #define Inaccurate_Divide for IEEE-format with correctly rounded * products but inaccurate quotients, e.g., for Intel i860. - * #define Just_16 to store 16 bits per 32-bit long when doing high-precision - * integer arithmetic. Whether this speeds things up or slows things - * down depends on the machine and the number being converted. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. * #define KR_headers for old-style C function headers. * #define Bad_float_h if your system lacks a float.h or if it does not * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #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. + * #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, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions 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.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod 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 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #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 + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #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. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. */ - #if defined(i386) || defined(mips) && defined(MIPSEL) || defined (__arm__) -#define IEEE_8087 +# define IEEE_8087 #elif defined(__x86_64__) || defined(__alpha__) -#define IEEE_8087 +# define IEEE_8087 #elif defined(__ia64) -# ifdef __hpux -# define IEEE_MC68k -# else -# define IEEE_8087 -# endif +# ifdef __hpux +# define IEEE_MC68k +# else +# define IEEE_8087 +# endif #elif defined(__hppa) -# define IEEE_MC68k +# define IEEE_MC68k #else #define IEEE_MC68k @@ -172,45 +204,58 @@ static char sccsid[] = "@(#)strtod.c 8.1 (Berkeley) 6/4/93"; #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} #endif -#include -#ifdef __cplusplus -#include "malloc.h" -#include "memory.h" -#else -#ifndef KR_headers #include "stdlib.h" #include "string.h" + +#undef USE_LOCALE +#ifdef USE_LOCALE +#include "locale.h" +#endif + +#ifdef MALLOC +#ifdef KR_headers +extern char *MALLOC(); #else -#include "malloc.h" -#include "memory.h" +extern void *MALLOC(size_t); #endif +#else +#define MALLOC malloc #endif -#include "errno.h" -#include -#ifdef Bad_float_h -#undef __STDC__ +#define Omit_Private_Memory +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow #ifdef IEEE_MC68k -#define IEEE_ARITHMETIC +#define IEEE_Arith #endif #ifdef IEEE_8087 -#define IEEE_ARITHMETIC +#define IEEE_Arith #endif -#ifdef IEEE_ARITHMETIC + +#include "errno.h" + +#ifdef Bad_float_h + +#ifdef IEEE_Arith #define DBL_DIG 15 #define DBL_MAX_10_EXP 308 #define DBL_MAX_EXP 1024 #define FLT_RADIX 2 -#define FLT_ROUNDS 1 -#define DBL_MAX 1.7976931348623157e+308 -#endif +#endif /*IEEE_Arith*/ #ifdef IBM #define DBL_DIG 16 #define DBL_MAX_10_EXP 75 #define DBL_MAX_EXP 63 #define FLT_RADIX 16 -#define FLT_ROUNDS 0 #define DBL_MAX 7.2370055773322621e+75 #endif @@ -219,16 +264,17 @@ static char sccsid[] = "@(#)strtod.c 8.1 (Berkeley) 6/4/93"; #define DBL_MAX_10_EXP 38 #define DBL_MAX_EXP 127 #define FLT_RADIX 2 -#define FLT_ROUNDS 1 #define DBL_MAX 1.7014118346046923e+38 #endif #ifndef LONG_MAX #define LONG_MAX 2147483647 #endif -#else + +#else /* ifndef Bad_float_h */ #include "float.h" -#endif +#endif /* Bad_float_h */ + #ifndef __MATH_H__ #include "math.h" #endif @@ -245,16 +291,14 @@ extern "C" { #endif #endif -#ifdef Unsigned_Shifts -#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000; -#else -#define Sign_Extend(a,b) /*no-op*/ -#endif - #if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #endif +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] @@ -262,6 +306,16 @@ Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #define word0(x) ((ULong *)&x)[0] #define word1(x) ((ULong *)&x)[1] #endif +#else +#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 /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is @@ -269,10 +323,10 @@ Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. */ #if defined(IEEE_8087) + defined(VAX) #define Storeinc(a,b,c) do { (((unsigned short *)a)[1] = (unsigned short)b, \ -((unsigned short *)a)[0] = (unsigned short)c); a ++; } while (0) +((unsigned short *)a)[0] = (unsigned short)c, a++) } while (0) #else -#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ -((unsigned short *)a)[1] = (unsigned short)c, a++) +#define Storeinc(a,b,c) do { (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) } while (0) #endif /* #define P DBL_MANT_DIG */ @@ -281,7 +335,7 @@ Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ -#if defined(IEEE_8087) + defined(IEEE_MC68k) +#ifdef IEEE_Arith #define Exp_shift 20 #define Exp_shift1 20 #define Exp_msk1 0x100000 @@ -289,7 +343,6 @@ Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #define Exp_mask 0x7ff00000 #define P 53 #define Bias 1023 -#define IEEE_Arith #define Emin (-1022) #define Exp_1 0x3ff00000 #define Exp_11 0x3ff00000 @@ -307,11 +360,38 @@ Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #define Tiny1 1 #define Quick_max 14 #define Int_max 14 -#define Infinite(x) (word0(x) == 0x7ff00000) /* sufficient test for here */ +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#define Rounding rounding +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS #else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT #undef Sudden_Underflow #define Sudden_Underflow #ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 #define Exp_shift 24 #define Exp_shift1 24 #define Exp_msk1 0x1000000 @@ -336,6 +416,8 @@ Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #define Quick_max 14 #define Int_max 15 #else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 #define Exp_shift 23 #define Exp_shift1 7 #define Exp_msk1 0x80 @@ -359,8 +441,8 @@ Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #define Tiny1 0 #define Quick_max 15 #define Int_max 15 -#endif -#endif +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ #ifndef IEEE_Arith #define ROUND_BIASED @@ -382,23 +464,46 @@ extern double rnd_prod(double, double), rnd_quot(double, double); #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff -#ifndef Just_16 -/* When Pack_32 is not defined, we store 16 bits per 32-bit long. +#ifndef Pack_32 +#define Pack_32 +#endif + +#ifdef KR_headers +#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) +#else +#define FFFFFFFF 0xffffffffUL +#endif + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. * This makes some inner loops simpler and sometimes saves work * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per long. + * slower. Hence the default is now to store 32 bits per Long. */ -#ifndef Pack_32 -#define Pack_32 #endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ #endif #define Kmax 15 #ifdef __cplusplus -extern "C" double bsd_strtod(const char *s00, char **se); -extern "C" char *__dtoa(double d, int mode, int ndigits, - int *decpt, int *sign, char **rve, char **resultp); +extern "C" double strtod(const char *s00, char **se); +extern "C" char *dtoa(double d, int mode, int ndigits, + int *decpt, int *sign, char **rve); #endif struct @@ -406,10 +511,12 @@ Bigint { struct Bigint *next; int k, maxwds, sign, wds; ULong x[1]; -}; + }; typedef struct Bigint Bigint; + static Bigint *freelist[Kmax+1]; + static Bigint * Balloc #ifdef KR_headers @@ -420,14 +527,35 @@ Balloc { int x; Bigint *rv; +#ifndef Omit_Private_Memory + unsigned int len; +#endif - x = 1 << k; - rv = (Bigint *)malloc(sizeof(Bigint) + (x-1)*sizeof(Long)); - rv->k = k; - rv->maxwds = x; + ACQUIRE_DTOA_LOCK(0); + if ((rv = freelist[k])) { + freelist[k] = rv->next; + } + else { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (pmem_next - private_mem + len <= PRIVATE_mem) { + rv = (Bigint*)pmem_next; + pmem_next += len; + } + else + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); rv->sign = rv->wds = 0; return rv; -} + } static void Bfree @@ -437,8 +565,13 @@ Bfree (Bigint *v) #endif { - free(v); -} + if (v) { + ACQUIRE_DTOA_LOCK(0); + v->next = freelist[v->k]; + freelist[v->k] = v; + FREE_DTOA_LOCK(0); + } + } #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int)) @@ -452,40 +585,53 @@ multadd #endif { int i, wds; - ULong *x, y; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; #ifdef Pack_32 ULong xi, z; +#endif #endif Bigint *b1; wds = b->wds; x = b->x; i = 0; + carry = a; do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = y & FFFFFFFF; +#else #ifdef Pack_32 xi = *x; - y = (xi & 0xffff) * m + a; + y = (xi & 0xffff) * m + carry; z = (xi >> 16) * m + (y >> 16); - a = (int)(z >> 16); + carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); #else - y = *x * m + a; - a = (int)(y >> 16); + y = *x * m + carry; + carry = y >> 16; *x++ = y & 0xffff; #endif - } while (++i < wds); - if (a) { +#endif + } + while(++i < wds); + if (carry) { if (wds >= b->maxwds) { b1 = Balloc(b->k+1); Bcopy(b1, b); Bfree(b); b = b1; } - b->x[wds++] = a; + b->x[wds++] = carry; b->wds = wds; - } + } return b; -} + } static Bigint * s2b @@ -500,7 +646,7 @@ s2b Long x, y; x = (nd + 8) / 9; - for (k = 0, y = 1; x > y; y <<= 1, k++) ; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 b = Balloc(k); b->x[0] = y9; @@ -514,16 +660,16 @@ s2b i = 9; if (9 < nd0) { s += 9; - do - b = multadd(b, 10, *s++ - '0'); - while (++i < nd0); + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); s++; - } else + } + else s += 10; - for (; i < nd; i++) + for(; i < nd; i++) b = multadd(b, 10, *s++ - '0'); return b; -} + } static int hi0bits @@ -538,26 +684,26 @@ hi0bits if (!(x & 0xffff0000)) { k = 16; x <<= 16; - } + } if (!(x & 0xff000000)) { k += 8; x <<= 8; - } + } if (!(x & 0xf0000000)) { k += 4; x <<= 4; - } + } if (!(x & 0xc0000000)) { k += 2; x <<= 2; - } + } if (!(x & 0x80000000)) { k++; if (!(x & 0x40000000)) return 32; - } + } return k; -} + } static int lo0bits @@ -576,36 +722,36 @@ lo0bits if (x & 2) { *y = x >> 1; return 1; - } + } *y = x >> 2; return 2; - } + } k = 0; if (!(x & 0xffff)) { k = 16; x >>= 16; - } + } if (!(x & 0xff)) { k += 8; x >>= 8; - } + } if (!(x & 0xf)) { k += 4; x >>= 4; - } + } if (!(x & 0x3)) { k += 2; x >>= 2; - } + } if (!(x & 1)) { k++; x >>= 1; - if (!x & 1) + if (!x) return 32; - } + } *y = x; return k; -} + } static Bigint * i2b @@ -633,17 +779,22 @@ mult { Bigint *c; int k, wa, wb, wc; - ULong carry, y, z; ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; #ifdef Pack_32 ULong z2; +#endif #endif if (a->wds < b->wds) { c = a; a = b; b = c; - } + } k = a->k; wa = a->wds; wb = b->wds; @@ -651,17 +802,32 @@ mult if (wc > a->maxwds) k++; c = Balloc(k); - for (x = c->x, xa = x + wc; x < xa; x++) + for(x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; xae = xa + wa; xb = b->x; xbe = xb + wb; xc0 = c->x; - +#ifdef ULLong + for(; xb < xbe; xc0++) { + if ((y = *xb++)) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = z & FFFFFFFF; + } + while(x < xae); + *xc = carry; + } + } +#else #ifdef Pack_32 - for (; xb < xbe; xb++, xc0++) { - if ( (y = *xb & 0xffff) ) { + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { x = xa; xc = xc0; carry = 0; @@ -671,10 +837,11 @@ mult z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; carry = z2 >> 16; Storeinc(xc, z2, z); - } while (x < xae); + } + while(x < xae); *xc = carry; - } - if ( (y = *xb >> 16) ) { + } + if (y = *xb >> 16) { x = xa; xc = xc0; carry = 0; @@ -685,12 +852,13 @@ mult Storeinc(xc, z, z2); z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; carry = z2 >> 16; - } while (x < xae); + } + while(x < xae); *xc = z2; + } } - } #else - for (; xb < xbe; xc0++) { + for(; xb < xbe; xc0++) { if (y = *xb++) { x = xa; xc = xc0; @@ -699,15 +867,17 @@ mult z = *x++ * y + *xc + carry; carry = z >> 16; *xc++ = z & 0xffff; - } while (x < xae); + } + while(x < xae); *xc = carry; + } } - } #endif - for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; c->wds = wc; return c; -} + } static Bigint *p5s; @@ -723,32 +893,50 @@ pow5mult int i; static int p05[3] = { 5, 25, 125 }; - if ( (i = k & 3) ) + if ((i = k & 3)) b = multadd(b, p05[i-1], 0); if (!(k >>= 2)) return b; if (!(p5 = p5s)) { /* first time */ +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p5 = p5s)) { + p5 = p5s = i2b(625); + p5->next = 0; + } + FREE_DTOA_LOCK(1); +#else p5 = p5s = i2b(625); p5->next = 0; - } - for (;;) { +#endif + } + for(;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; - } + } if (!(k >>= 1)) break; if (!(p51 = p5->next)) { +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + FREE_DTOA_LOCK(1); +#else p51 = p5->next = mult(p5,p5); p51->next = 0; - } +#endif + } p5 = p51; - } + } return b; -} + } static Bigint * lshift @@ -769,11 +957,11 @@ lshift #endif k1 = b->k; n1 = n + b->wds + 1; - for (i = b->maxwds; n1 > i; i <<= 1) + for(i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(k1); x1 = b1->x; - for (i = 0; i < n; i++) + for(i = 0; i < n; i++) *x1++ = 0; x = b->x; xe = x + b->wds; @@ -784,10 +972,11 @@ lshift do { *x1++ = *x << k | z; z = *x++ >> k1; - } while (x < xe); - if ( (*x1 = z) ) + } + while(x < xe); + if ((*x1 = z)) ++n1; - } + } #else if (k &= 0xf) { k1 = 16 - k; @@ -795,19 +984,19 @@ lshift do { *x1++ = *x << k & 0xffff | z; z = *x++ >> k1; - } while (x < xe); + } + while(x < xe); if (*x1 = z) ++n1; - } + } #endif - else - do - *x1++ = *x++; - while (x < xe); + else do + *x1++ = *x++; + while(x < xe); b1->wds = n1 - 1; Bfree(b); return b1; -} + } static int cmp @@ -834,14 +1023,14 @@ cmp xa = xa0 + j; xb0 = b->x; xb = xb0 + j; - for (;;) { + for(;;) { if (*--xa != *--xb) return *xa < *xb ? -1 : 1; if (xa <= xa0) break; - } + } return 0; -} + } static Bigint * diff @@ -853,10 +1042,14 @@ diff { Bigint *c; int i, wa, wb; - Long borrow, y; /* We need signed shifts here. */ ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; #ifdef Pack_32 - Long z; + ULong z; +#endif #endif i = cmp(a,b); @@ -865,13 +1058,14 @@ diff c->wds = 1; c->x[0] = 0; return c; - } + } if (i < 0) { c = a; a = b; b = c; i = 1; - } else + } + else i = 0; c = Balloc(a->k); c->sign = i; @@ -883,44 +1077,54 @@ diff xbe = xb + wb; xc = c->x; borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } +#else #ifdef Pack_32 do { - y = (*xa & 0xffff) - (*xb & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*xa++ >> 16) - (*xb++ >> 16) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); - } while (xb < xbe); - while (xa < xae) { - y = (*xa & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*xa++ >> 16) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); - } + } #else do { - y = *xa++ - *xb++ + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; - } while (xb < xbe); - while (xa < xae) { - y = *xa++ + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; - } + } +#endif #endif - while (!*--xc) + while(!*--xc) wa--; c->wds = wa; return c; -} + } static double ulp @@ -934,29 +1138,35 @@ ulp double a; L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow #ifndef Sudden_Underflow if (L > 0) { #endif +#endif #ifdef IBM L |= Exp_msk1 >> 4; #endif word0(a) = L; word1(a) = 0; +#ifndef Avoid_Underflow #ifndef Sudden_Underflow - } else { + } + else { L = -L >> Exp_shift; if (L < Exp_shift) { word0(a) = 0x80000 >> L; word1(a) = 0; - } else { + } + else { word0(a) = 0; L -= Exp_shift; - word1(a) = L >= 31 ? 1 : 1 << (31 - L); + word1(a) = L >= 31 ? 1 : 1 << 31 - L; + } } - } #endif - return a; -} +#endif + return dval(a); + } static double b2d @@ -988,18 +1198,19 @@ b2d if (k < Ebits) { d0 = Exp_1 | (y >> (Ebits - k)); w = xa > xa0 ? *--xa : 0; - d1 = (y << ((32-Ebits) + k)) | (w >> (Ebits - k)); + d1 = y << ((32-Ebits) + k) | (w >> (Ebits - k)); goto ret_d; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { - d0 = Exp_1 | (y << k) | (z >> (32 - k)); + d0 = Exp_1 | y << k | (z >> (32 - k)); y = xa > xa0 ? *--xa : 0; - d1 = (z << k) | (y >> (32 - k)); - } else { + d1 = z << k | (y >> (32 - k)); + } + else { d0 = Exp_1 | y; d1 = z; - } + } #else if (k < Ebits + 16) { z = xa > xa0 ? *--xa : 0; @@ -1008,7 +1219,7 @@ b2d y = xa > xa0 ? *--xa : 0; d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; goto ret_d; - } + } z = xa > xa0 ? *--xa : 0; w = xa > xa0 ? *--xa : 0; k -= Ebits + 16; @@ -1024,8 +1235,8 @@ b2d #undef d0 #undef d1 #endif - return d; -} + return dval(d); + } static Bigint * d2b @@ -1036,8 +1247,11 @@ d2b #endif { Bigint *b; - int de, i, k; + int de, k; ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif #ifdef VAX ULong d0, d1; d0 = word0(d) >> 16 | word0(d) << 16; @@ -1062,28 +1276,35 @@ d2b z |= Exp_msk11; #endif #else - if ( (de = (int)(d0 >> Exp_shift)) ) + if ((de = (int)(d0 >> Exp_shift))) z |= Exp_msk1; #endif #ifdef Pack_32 - if ( (y = d1) ) { - if ( (k = lo0bits(&y)) ) { + if ((y = d1)) { + if ((k = lo0bits(&y))) { x[0] = y | (z << (32 - k)); z >>= k; } else x[0] = y; - i = b->wds = (x[1] = z) ? 2 : 1; - } else { +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { #ifdef DEBUG if (!z) Bug("Zero passed to d2b"); #endif k = lo0bits(&z); x[0] = z; - i = b->wds = 1; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; k += 32; - } + } #else if (y = d1) { if (k = lo0bits(&y)) @@ -1092,21 +1313,23 @@ d2b x[1] = z >> k - 16 & 0xffff; x[2] = z >> k; i = 2; - } else { + } + else { x[0] = y & 0xffff; x[1] = y >> 16 | z << 16 - k & 0xffff; x[2] = z >> k & 0xffff; x[3] = z >> k+16; i = 3; - } + } else { x[0] = y & 0xffff; x[1] = y >> 16; x[2] = z & 0xffff; x[3] = z >> 16; i = 3; + } } - } else { + else { #ifdef DEBUG if (!z) Bug("Zero passed to d2b"); @@ -1115,14 +1338,15 @@ d2b if (k >= 16) { x[0] = z; i = 0; - } else { + } + else { x[0] = z & 0xffff; x[1] = z >> 16; i = 1; - } + } k += 32; - } - while (!x[i]) + } + while(!x[i]) --i; b->wds = i + 1; #endif @@ -1137,17 +1361,18 @@ d2b *bits = P - k; #endif #ifndef Sudden_Underflow - } else { + } + else { *e = de - Bias - (P-1) + 1 + k; #ifdef Pack_32 *bits = 32*i - hi0bits(x[i-1]); #else *bits = (i+2)*16 - hi0bits(x[i]); #endif - } + } #endif return b; -} + } #undef d0 #undef d1 @@ -1162,8 +1387,8 @@ ratio double da, db; int k, ka, kb; - da = b2d(a, &ka); - db = b2d(b, &kb); + dval(da) = b2d(a, &ka); + dval(db) = b2d(b, &kb); #ifdef Pack_32 k = ka - kb + 32*(a->wds - b->wds); #else @@ -1173,25 +1398,26 @@ ratio if (k > 0) { word0(da) += (k >> 2)*Exp_msk1; if (k &= 3) - da *= 1 << k; - } else { + dval(da) *= 1 << k; + } + else { k = -k; word0(db) += (k >> 2)*Exp_msk1; if (k &= 3) - db *= 1 << k; - } + dval(db) *= 1 << k; + } #else if (k > 0) word0(da) += k*Exp_msk1; else { k = -k; word0(db) += k*Exp_msk1; - } + } #endif - return da / db; -} + return dval(da) / dval(db); + } - static double + static CONST double tens[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, @@ -1201,31 +1427,134 @@ tens[] = { #endif }; - static double + static CONST double #ifdef IEEE_Arith bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; -static double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-53 */ +#else + 1e-256 +#endif + }; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 #define n_bigtens 5 #else #ifdef IBM bigtens[] = { 1e16, 1e32, 1e64 }; -static double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; #define n_bigtens 3 #else bigtens[] = { 1e16, 1e32 }; -static double tinytens[] = { 1e-16, 1e-32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; #define n_bigtens 2 #endif #endif +#ifndef IEEE_Arith +#undef INFNAN_CHECK +#endif + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + + static int +match +#ifdef KR_headers + (sp, t) char **sp, *t; +#else + (CONST char **sp, char *t) +#endif +{ + int c, d; + CONST char *s = *sp; + + while(d = *t++) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; + } + +#ifndef No_Hex_NaN + static void +hexnan +#ifdef KR_headers + (rvp, sp) double *rvp; CONST char **sp; +#else + (double *rvp, CONST char **sp) +#endif +{ + ULong c, x[2]; + CONST char *s; + int havedig, udx0, xshift; + + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + while(c = *(CONST unsigned char*)++s) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c += 10 - 'a'; + else if (c >= 'A' && c <= 'F') + c += 10 - 'A'; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(*rvp) = Exp_mask | x[0]; + word1(*rvp) = x[1]; + } + } +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + double -bsd_strtod +mono_strtod #ifdef KR_headers (s00, se) CONST char *s00; char **se; #else (CONST char *s00, char **se) #endif { +#ifdef Avoid_Underflow + int scale; +#endif int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; CONST char *s, *s0, *s1; @@ -1233,11 +1562,19 @@ bsd_strtod Long L; ULong y, z; Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; - char decimal_point = '.'; +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef USE_LOCALE + CONST char *s2; +#endif sign = nz0 = nz = 0; - rv = 0.; - for (s = s00;;s++) switch(*s) { + dval(rv) = 0.; + for(s = s00;;s++) switch(*s) { case '-': sign = 1; /* no break */ @@ -1246,47 +1583,70 @@ bsd_strtod goto break2; /* no break */ case 0: - s = s00; - goto ret; + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; default: - if (isspace((unsigned char)*s)) - continue; goto break2; - } + } break2: if (*s == '0') { nz0 = 1; - while (*++s == '0') ; + while(*++s == '0') ; if (!*s) goto ret; - } + } s0 = s; y = z = 0; - for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) if (nd < 9) y = 10*y + c - '0'; else if (nd < 16) z = 10*z + c - '0'; nd0 = nd; - if ((char)c == decimal_point) { +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for(;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { c = *++s; if (!nd) { - for (; c == '0'; c = *++s) + for(; c == '0'; c = *++s) nz++; if (c > '0' && c <= '9') { s0 = s; nf += nz; nz = 0; goto have_dig; - } + } goto dig_done; - } - for (; c >= '0' && c <= '9'; c = *++s) { + } + for(; c >= '0' && c <= '9'; c = *++s) { have_dig: nz++; if (c -= '0') { nf += nz; - for (i = 1; i < nz; i++) + for(i = 1; i < nz; i++) if (nd++ < 9) y *= 10; else if (nd <= DBL_DIG + 1) @@ -1296,16 +1656,15 @@ bsd_strtod else if (nd <= DBL_DIG + 1) z = 10*z + c; nz = 0; + } } } - } dig_done: e = 0; if (c == 'e' || c == 'E') { if (!nd && !nz && !nz0) { - s = s00; - goto ret; - } + goto ret0; + } s00 = s; esign = 0; switch(c = *++s) { @@ -1313,14 +1672,14 @@ bsd_strtod esign = 1; case '+': c = *++s; - } + } if (c >= '0' && c <= '9') { - while (c == '0') + while(c == '0') c = *++s; if (c > '0' && c <= '9') { L = c - '0'; s1 = s; - while ((c = *++s) >= '0' && c <= '9') + while((c = *++s) >= '0' && c <= '9') L = 10*L + c - '0'; if (s - s1 > 8 || L > 19999) /* Avoid confusion from exponents @@ -1331,16 +1690,48 @@ bsd_strtod e = (int)L; if (esign) e = -e; - } else + } + else e = 0; - } else + } + else s = s00; - } + } if (!nd) { - if (!nz && !nz0) + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + switch(c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(rv) = 0x7ff00000; + word1(rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(rv) = NAN_WORD0; + word1(rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ + ret0: s = s00; + sign = 0; + } goto ret; - } + } e1 = e -= nf; /* Now we have nd0 digits, starting at s0, followed by a @@ -1351,12 +1742,20 @@ bsd_strtod if (!nd0) nd0 = nd; k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - rv = y; - if (k > 9) - rv = tens[k - 9] * rv + z; + dval(rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(rv) = tens[k - 9] * dval(rv) + z; + } + bd0 = 0; if (nd <= DBL_DIG #ifndef RND_PRODQUOT - && FLT_ROUNDS == 1 +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif #endif ) { if (!e) @@ -1366,7 +1765,14 @@ bsd_strtod #ifdef VAX goto vax_ovfl_check; #else - /* rv = */ rounded_product(rv, tens[e]); +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(rv), tens[e]); goto ret; #endif } @@ -1375,106 +1781,186 @@ bsd_strtod /* A fancier test would sometimes let us do * this for larger i values. */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif e -= i; - rv *= tens[i]; + dval(rv) *= tens[i]; #ifdef VAX /* VAX exponent range is so narrow we must * worry about overflow here... */ vax_ovfl_check: word0(rv) -= P*Exp_msk1; - /* rv = */ rounded_product(rv, tens[e]); + /* rv = */ rounded_product(dval(rv), tens[e]); if ((word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) goto ovfl; word0(rv) += P*Exp_msk1; #else - /* rv = */ rounded_product(rv, tens[e]); + /* rv = */ rounded_product(dval(rv), tens[e]); #endif goto ret; + } } - } #ifndef Inaccurate_Divide else if (e >= -Ten_pmax) { - /* rv = */ rounded_quotient(rv, tens[-e]); +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(rv), tens[-e]); goto ret; - } + } #endif - } + } e1 += nd - k; +#ifdef IEEE_Arith +#ifdef SET_INEXACT + inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + /* Get starting approximation = rv * 10**e1 */ if (e1 > 0) { - if ( (i = e1 & 15) ) - rv *= tens[i]; - if ( (e1 &= ~15) ) { + if ((i = e1 & 15)) + dval(rv) *= tens[i]; + if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: +#ifndef NO_ERRNO errno = ERANGE; -#ifdef __STDC__ - rv = HUGE_VAL; -#else +#endif /* Can't trust HUGE_VAL */ #ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(rv) = Big0; + word1(rv) = Big1; + break; + default: + word0(rv) = Exp_mask; + word1(rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ word0(rv) = Exp_mask; word1(rv) = 0; -#else +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(rv0) = 1e300; + dval(rv0) *= dval(rv0); +#endif +#else /*IEEE_Arith*/ word0(rv) = Big0; word1(rv) = Big1; -#endif -#endif +#endif /*IEEE_Arith*/ + if (bd0) + goto retfree; goto ret; - } - if (e1 >>= 4) { - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - rv *= bigtens[j]; - /* The last multiplication could overflow. */ - word0(rv) -= P*Exp_msk1; - rv *= bigtens[j]; - if ((z = word0(rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-P)) - goto ovfl; - if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { - /* set to largest number */ - /* (Can't trust DBL_MAX) */ - word0(rv) = Big0; - word1(rv) = Big1; - } - else - word0(rv) += P*Exp_msk1; + } + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(rv) -= P*Exp_msk1; + dval(rv) *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; } } - } else if (e1 < 0) { + else if (e1 < 0) { e1 = -e1; - if ( (i = e1 & 15) ) - rv /= tens[i]; - if ( (e1 &= ~15) ) { - e1 >>= 4; - for (j = 0; e1 > 1; j++, e1 >>= 1) + if ((i = e1 & 15)) + dval(rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; zap j low bits */ + if (j >= 32) { + word1(rv) = 0; + if (j >= 53) + word0(rv) = (P+2)*Exp_msk1; + else + word0(rv) &= 0xffffffff << (j-32); + } + else + word1(rv) &= 0xffffffff << j; + } +#else + for(j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) - rv *= tinytens[j]; + dval(rv) *= tinytens[j]; /* The last multiplication could underflow. */ - rv0 = rv; - rv *= tinytens[j]; - if (!rv) { - rv = 2.*rv0; - rv *= tinytens[j]; - if (!rv) { + dval(rv0) = dval(rv); + dval(rv) *= tinytens[j]; + if (!dval(rv)) { + dval(rv) = 2.*dval(rv0); + dval(rv) *= tinytens[j]; +#endif + if (!dval(rv)) { undfl: - rv = 0.; + dval(rv) = 0.; +#ifndef NO_ERRNO errno = ERANGE; +#endif + if (bd0) + goto retfree; goto ret; } +#ifndef Avoid_Underflow word0(rv) = Tiny0; word1(rv) = Tiny1; /* The refinement below will clean * this approximation up. */ + } +#endif } } - } /* Now the hard part -- adjusting rv to the correct value.*/ @@ -1482,39 +1968,57 @@ bsd_strtod bd0 = s2b(s0, nd0, nd, y); - for (;;) { + for(;;) { bd = Balloc(bd0->k); Bcopy(bd, bd0); - bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ bs = i2b(1); if (e >= 0) { bb2 = bb5 = 0; bd2 = bd5 = e; - } else { + } + else { bb2 = bb5 = -e; bd2 = bd5 = 0; - } + } if (bbe >= 0) bb2 += bbe; else bd2 -= bbe; bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + j = bbe - scale; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#else /*Avoid_Underflow*/ #ifdef Sudden_Underflow #ifdef IBM j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); #else j = P + 1 - bbbits; #endif -#else - i = bbe + bbbits - 1; /* logb(rv) */ +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ - j = bbe + (P-Emin); + j += P - Emin; else j = P + 1 - bbbits; -#endif +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ bb2 += j; bd2 += j; +#ifdef Avoid_Underflow + bd2 += scale; +#endif i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; @@ -1541,22 +2045,138 @@ bsd_strtod dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (rounding) { + if (dsign) { + adj = 1.; + goto apply_adj; + } + } + else if (!dsign) { + adj = -1.; + if (!word1(rv) + && !(word0(rv) & Frac_mask)) { + y = word0(rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (cmp(delta, bs) <= 0) + adj = -0.5; + } + } + apply_adj: +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= + P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + dval(rv) += adj*ulp(dval(rv)); + word0(rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + dval(rv) += adj*ulp(dval(rv)); + } + break; + } + adj = ratio(delta, bs); + if (adj < 1.) + adj = 1.; + if (adj <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj; + if (y != adj) { + if (!((rounding>>1) ^ dsign)) + y++; + adj = y; + } + } +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + word0(rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + goto cont; + } +#endif /*Honor_FLT_ROUNDS*/ + if (i < 0) { /* Error is less than half an ulp -- check for * special case of mantissa a power of two. */ - if (dsign || word1(rv) || word0(rv) & Bndry_mask) + if (dsign || word1(rv) || word0(rv) & Bndry_mask +#ifdef IEEE_Arith +#ifdef Avoid_Underflow + || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(rv) & Exp_mask) <= Exp_msk1 +#endif +#endif + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + inexact = 0; +#endif break; + } delta = lshift(delta,Log2P); if (cmp(delta, bs) > 0) goto drop_down; break; - } + } if (i == 0) { /* exactly half-way between */ if (dsign) { if ((word0(rv) & Bndry_mask1) == Bndry_mask1 - && word1(rv) == 0xffffffff) { + && word1(rv) == ( +#ifdef Avoid_Underflow + (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { /*boundary case -- increment exponent*/ word0(rv) = (word0(rv) & Exp_mask) + Exp_msk1 @@ -1565,23 +2185,44 @@ bsd_strtod #endif ; word1(rv) = 0; +#ifdef Avoid_Underflow + dsign = 0; +#endif break; + } } - } else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { drop_down: /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow +#ifdef Sudden_Underflow /*{{*/ L = word0(rv) & Exp_mask; #ifdef IBM if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) #else if (L <= Exp_msk1) -#endif +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ goto undfl; L -= Exp_msk1; -#else +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (scale) { + L = word0(rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + goto undfl; + } + } +#endif /*Avoid_Underflow*/ L = (word0(rv) & Exp_mask) - Exp_msk1; -#endif +#endif /*Sudden_Underflow}}*/ word0(rv) = L | Bndry_mask1; word1(rv) = 0xffffffff; #ifdef IBM @@ -1589,24 +2230,27 @@ bsd_strtod #else break; #endif - } + } #ifndef ROUND_BIASED if (!(word1(rv) & LSB)) break; #endif if (dsign) - rv += ulp(rv); + dval(rv) += ulp(dval(rv)); #ifndef ROUND_BIASED else { - rv -= ulp(rv); + dval(rv) -= ulp(dval(rv)); #ifndef Sudden_Underflow - if (!rv) + if (!dval(rv)) goto undfl; #endif - } + } +#ifdef Avoid_Underflow + dsign = 1 - dsign; +#endif #endif break; - } + } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) aadj = aadj1 = 1.; @@ -1617,7 +2261,8 @@ bsd_strtod #endif aadj = 1.; aadj1 = -1.; - } else { + } + else { /* special case -- power of FLT_RADIX to be */ /* rounded down... */ @@ -1626,33 +2271,34 @@ bsd_strtod else aadj *= 0.5; aadj1 = -aadj; + } } - } else { + else { aadj *= 0.5; aadj1 = dsign ? aadj : -aadj; #ifdef Check_FLT_ROUNDS - switch(FLT_ROUNDS) { + switch(Rounding) { case 2: /* towards +infinity */ aadj1 -= 0.5; break; case 0: /* towards 0 */ case 3: /* towards -infinity */ aadj1 += 0.5; - } + } #else - if (FLT_ROUNDS == 0) + if (Flt_Rounds == 0) aadj1 += 0.5; -#endif - } +#endif /*Check_FLT_ROUNDS*/ + } y = word0(rv) & Exp_mask; /* Check for overflow */ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { - rv0 = rv; + dval(rv0) = dval(rv); word0(rv) -= P*Exp_msk1; - adj = aadj1 * ulp(rv); - rv += adj; + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; if ((word0(rv) & Exp_mask) >= Exp_msk1*(DBL_MAX_EXP+Bias-P)) { if (word0(rv0) == Big0 && word1(rv0) == Big1) @@ -1660,34 +2306,51 @@ bsd_strtod word0(rv) = Big0; word1(rv) = Big1; goto cont; - } else + } + else word0(rv) += P*Exp_msk1; - } else { + } + else { +#ifdef Avoid_Underflow + if (scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = aadj) <= 0) + z = 1; + aadj = z; + aadj1 = dsign ? aadj : -aadj; + } + word0(aadj1) += (2*P+1)*Exp_msk1 - y; + } + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; +#else #ifdef Sudden_Underflow if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { - rv0 = rv; + dval(rv0) = dval(rv); word0(rv) += P*Exp_msk1; - adj = aadj1 * ulp(rv); - rv += adj; + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; #ifdef IBM if ((word0(rv) & Exp_mask) < P*Exp_msk1) #else if ((word0(rv) & Exp_mask) <= P*Exp_msk1) #endif - { + { if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) goto undfl; word0(rv) = Tiny0; word1(rv) = Tiny1; goto cont; - } else + } + else word0(rv) -= P*Exp_msk1; - } else { - adj = aadj1 * ulp(rv); - rv += adj; - } -#else + } + else { + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; + } +#else /*Sudden_Underflow*/ /* Compute adj so that the IEEE rounding rules will * correctly round rv + adj in some half-way cases. * If rv * ulp(rv) is denormalized (i.e., @@ -1695,33 +2358,71 @@ bsd_strtod * trouble from bits lost to denormalization; * example: 1.2e-307 . */ - if (y <= (P-1)*Exp_msk1 && aadj >= 1.) { + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { aadj1 = (double)(int)(aadj + 0.5); if (!dsign) aadj1 = -aadj1; + } + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ } - adj = aadj1 * ulp(rv); - rv += adj; -#endif - } z = word0(rv) & Exp_mask; +#ifndef SET_INEXACT +#ifdef Avoid_Underflow + if (!scale) +#endif if (y == z) { /* Can we stop now? */ - L = aadj; + L = (Long)aadj; aadj -= L; /* The tolerances below are conservative. */ if (dsign || word1(rv) || word0(rv) & Bndry_mask) { if (aadj < .4999999 || aadj > .5000001) break; - } else if (aadj < .4999999/FLT_RADIX) + } + else if (aadj < .4999999/FLT_RADIX) break; - } + } +#endif cont: Bfree(bb); Bfree(bd); Bfree(bs); Bfree(delta); - } + } +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(rv0) = Exp_1 + (70 << Exp_shift); + word1(rv0) = 0; + dval(rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (scale) { + word0(rv0) = Exp_1 - 2*P*Exp_msk1; + word1(rv0) = 0; + dval(rv) *= dval(rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ + if (word0(rv) == 0 && word1(rv) == 0) + errno = ERANGE; +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (inexact && !(word0(rv) & Exp_mask)) { + /* set underflow bit */ + dval(rv0) = 1e-300; + dval(rv0) *= dval(rv0); + } +#endif + retfree: Bfree(bb); Bfree(bd); Bfree(bs); @@ -1730,8 +2431,8 @@ bsd_strtod ret: if (se) *se = (char *)s; - return sign ? -rv : rv; -} + return sign ? -dval(rv) : dval(rv); + } static int quorem @@ -1742,12 +2443,14 @@ quorem #endif { int n; - Long borrow, y; - ULong carry, q, ys; - ULong *bx, *bxe, *sx, *sxe; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; #ifdef Pack_32 - Long z; - ULong si, zs; + ULong si, z, zs; +#endif #endif n = S->wds; @@ -1770,34 +2473,40 @@ quorem borrow = 0; carry = 0; do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) * q + carry; zs = (si >> 16) * q + (ys >> 16); carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*bx >> 16) - (zs & 0xffff) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ * q + carry; carry = ys >> 16; - y = *bx - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif - } while (sx <= sxe); +#endif + } + while(sx <= sxe); if (!*bxe) { bx = b->x; - while (--bxe > bx && !*bxe) + while(--bxe > bx && !*bxe) --n; b->wds = n; + } } - } if (cmp(b, S) >= 0) { q++; borrow = 0; @@ -1805,42 +2514,116 @@ quorem bx = b->x; sx = S->x; do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) + carry; zs = (si >> 16) + (ys >> 16); carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*bx >> 16) - (zs & 0xffff) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ + carry; carry = ys >> 16; - y = *bx - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif - } while (sx <= sxe); +#endif + } + while(sx <= sxe); bx = b->x; bxe = bx + n; if (!*bxe) { - while (--bxe > bx && !*bxe) + while(--bxe > bx && !*bxe) --n; b->wds = n; + } } - } return q; -} + } + +#ifndef MULTIPLE_THREADS + static char *dtoa_result; +#endif + + static char * +#ifdef KR_headers +rv_alloc(i) int i; +#else +rv_alloc(int i) +#endif +{ + int j, k, *r; + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; + j <<= 1) + k++; + r = (int*)Balloc(k); + *r = k; + return +#ifndef MULTIPLE_THREADS + dtoa_result = +#endif + (char *)(r+1); + } + + static char * +#ifdef KR_headers +nrv_alloc(s, rve, n) char *s, **rve; int n; +#else +nrv_alloc(char *s, char **rve, int n) +#endif +{ + char *rv, *t; + + t = rv = rv_alloc(n); + while((*t = *s++)) t++; + if (rve) + *rve = t; + return rv; + } + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + +static void freedtoa (char *s); + +static void +#ifdef KR_headers +freedtoa(s) char *s; +#else +freedtoa(char *s) +#endif +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(b); +#ifndef MULTIPLE_THREADS + if (s == dtoa_result) + dtoa_result = 0; +#endif + } + +#if 0 /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate @@ -1867,18 +2650,17 @@ quorem * guarantee that the floating-point calculation has given * the correctly rounded result. For k requested digits and * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the long + * something like 10^(k-15) that we must resort to the Long * calculation. */ -char * -__bsd_dtoa + char * +dtoa #ifdef KR_headers - (d, mode, ndigits, decpt, sign, rve, resultp) - double d; int mode, ndigits, *decpt, *sign; char **rve, **resultp; + (d, mode, ndigits, decpt, sign, rve) + double d; int mode, ndigits, *decpt, *sign; char **rve; #else - (double d, int mode, int ndigits, int *decpt, int *sign, char **rve, - char **resultp) + (double d, int mode, int ndigits, int *decpt, int *sign, char **rve) #endif { /* Arguments ndigits, decpt, sign are similar to those @@ -1900,14 +2682,14 @@ __bsd_dtoa gives a return value similar to that from fcvt, except that trailing zeros are suppressed, and ndigits can be negative. - 4-9 should give the same return values as 2-3, i.e., - 4 <= mode <= 9 ==> same return as mode - 2 + (mode & 1). These modes are mainly for - debugging; often they run slower but sometimes - faster than modes 2-3. - 4,5,8,9 ==> left-to-right digit generation. - 6-9 ==> don't try fast floating-point estimate - (if applicable). + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). Values of mode other than 0-9 are treated as mode 0. @@ -1926,12 +2708,25 @@ __bsd_dtoa Bigint *b, *b1, *delta, *mlo, *mhi, *S; double d2, ds, eps; char *s, *s0; +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif if (word0(d) & Sign_bit) { /* set sign for everything, including 0's and NaNs */ *sign = 1; word0(d) &= ~Sign_bit; /* clear sign bit */ - } + } else *sign = 0; @@ -1941,51 +2736,50 @@ __bsd_dtoa #else if (word0(d) == 0x8000) #endif - { + { /* Infinity or NaN */ - const char *ss; *decpt = 9999; - ss = -#ifdef IEEE_Arith - !word1(d) && !(word0(d) & 0xfffff) ? "Infinity" : -#endif - "NaN"; - *resultp = s = malloc (strlen (ss) + 1); - strcpy (s, ss); - if (rve) - *rve = #ifdef IEEE_Arith - s[3] ? s + 8 : + if (!word1(d) && !(word0(d) & 0xfffff)) + return nrv_alloc("Infinity", rve, 8); #endif - s + 3; - return s; - } + return nrv_alloc("NaN", rve, 3); + } #endif #ifdef IBM - d += 0; /* normalize */ + dval(d) += 0; /* normalize */ #endif - if (!d) { + if (!dval(d)) { *decpt = 1; - *resultp = s = malloc (2); - s [0] = '0'; - s [1] = 0; - if (rve) - *rve = s + 1; - return s; - } + return nrv_alloc("0", rve, 1); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (*sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif - b = d2b(d, &be, &bbits); + b = d2b(dval(d), &be, &bbits); #ifdef Sudden_Underflow i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else - if ( (i = (int)((word0(d) >> Exp_shift1) & (Exp_mask>>Exp_shift1))) ) { + if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) { #endif - d2 = d; + dval(d2) = dval(d); word0(d2) &= Frac_mask1; word0(d2) |= Exp_11; #ifdef IBM - if ( (j = 11 - hi0bits(word0(d2) & Frac_mask)) ) - d2 /= 1 << j; + if (j = 11 - hi0bits(word0(d2) & Frac_mask)) + dval(d2) /= 1 << j; #endif /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 @@ -2017,52 +2811,63 @@ __bsd_dtoa #endif #ifndef Sudden_Underflow denorm = 0; - } else { + } + else { /* d is denormalized */ i = bbits + be + (Bias + (P-1) - 1); - x = i > 32 ? ((word0(d) << (64 - i)) | (word1(d) >> (i - 32))) - : (word1(d) << (32 - i)); - d2 = x; + x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32 + : word1(d) << 32 - i; + dval(d2) = x; word0(d2) -= 31*Exp_msk1; /* adjust exponent */ i -= (Bias + (P-1) - 1) + 1; denorm = 1; - } + } #endif - ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; k = (int)ds; if (ds < 0. && ds != k) k--; /* want k = floor(ds) */ k_check = 1; if (k >= 0 && k <= Ten_pmax) { - if (d < tens[k]) + if (dval(d) < tens[k]) k--; k_check = 0; - } + } j = bbits - i - 1; if (j >= 0) { b2 = 0; s2 = j; - } else { + } + else { b2 = -j; s2 = 0; - } + } if (k >= 0) { b5 = 0; s5 = k; s2 += k; - } else { + } + else { b2 -= k; b5 = -k; s5 = 0; - } + } if (mode < 0 || mode > 9) mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + if (mode > 5) { mode -= 4; try_quick = 0; - } + } leftright = 1; switch(mode) { case 0: @@ -2088,16 +2893,20 @@ __bsd_dtoa ilim1 = i - 1; if (i <= 0) i = 1; - } - *resultp = (char *) malloc(i + 1); - s = s0 = *resultp; + } + s = s0 = rv_alloc(i); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && rounding != 1) + leftright = 0; +#endif if (ilim >= 0 && ilim <= Quick_max && try_quick) { /* Try to get by with floating-point arithmetic. */ i = 0; - d2 = d; + dval(d2) = dval(d); k0 = k; ilim0 = ilim; ieps = 2; /* conservative */ @@ -2107,89 +2916,92 @@ __bsd_dtoa if (j & Bletch) { /* prevent overflows */ j &= Bletch - 1; - d /= bigtens[n_bigtens-1]; + dval(d) /= bigtens[n_bigtens-1]; ieps++; - } - for (; j; j >>= 1, i++) + } + for(; j; j >>= 1, i++) if (j & 1) { ieps++; ds *= bigtens[i]; - } - d /= ds; - } else if ( (j1 = -k) ) { - d *= tens[j1 & 0xf]; - for (j = j1 >> 4; j; j >>= 1, i++) + } + dval(d) /= ds; + } + else if (j1 = -k) { + dval(d) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) if (j & 1) { ieps++; - d *= bigtens[i]; - } - } - if (k_check && d < 1. && ilim > 0) { + dval(d) *= bigtens[i]; + } + } + if (k_check && dval(d) < 1. && ilim > 0) { if (ilim1 <= 0) goto fast_failed; ilim = ilim1; k--; - d *= 10.; + dval(d) *= 10.; ieps++; - } - eps = ieps*d + 7.; + } + dval(eps) = ieps*dval(d) + 7.; word0(eps) -= (P-1)*Exp_msk1; if (ilim == 0) { S = mhi = 0; - d -= 5.; - if (d > eps) + dval(d) -= 5.; + if (dval(d) > dval(eps)) goto one_digit; - if (d < -eps) + if (dval(d) < -dval(eps)) goto no_digits; goto fast_failed; - } + } #ifndef No_leftright if (leftright) { /* Use Steele & White method of only * generating digits needed. */ - eps = 0.5/tens[ilim-1] - eps; - for (i = 0;;) { - L = d; - d -= L; + dval(eps) = 0.5/tens[ilim-1] - dval(eps); + for(i = 0;;) { + L = dval(d); + dval(d) -= L; *s++ = '0' + (int)L; - if (d < eps) + if (dval(d) < dval(eps)) goto ret1; - if (1. - d < eps) + if (1. - dval(d) < dval(eps)) goto bump_up; if (++i >= ilim) break; - eps *= 10.; - d *= 10.; + dval(eps) *= 10.; + dval(d) *= 10.; + } } - } else { + else { #endif /* Generate ilim digits, then fix them up. */ - eps *= tens[ilim-1]; - for (i = 1;; i++, d *= 10.) { - L = d; - d -= L; + dval(eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d)); + if (!(dval(d) -= L)) + ilim = i; *s++ = '0' + (int)L; if (i == ilim) { - if (d > 0.5 + eps) + if (dval(d) > 0.5 + dval(eps)) goto bump_up; - else if (d < 0.5 - eps) { - while (*--s == '0'); + else if (dval(d) < 0.5 - dval(eps)) { + while(*--s == '0'); s++; goto ret1; - } + } break; + } } - } #ifndef No_leftright - } + } #endif fast_failed: s = s0; - d = d2; + dval(d) = dval(d2); k = k0; ilim = ilim0; - } + } /* Do we have a "small" integer? */ @@ -2198,79 +3010,75 @@ __bsd_dtoa ds = tens[k]; if (ndigits < 0 && ilim <= 0) { S = mhi = 0; - if (ilim < 0 || d <= 5*ds) + if (ilim < 0 || dval(d) <= 5*ds) goto no_digits; goto one_digit; - } - for (i = 1;; i++) { - L = d / ds; - d -= L*ds; + } + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d) / ds); + dval(d) -= L*ds; #ifdef Check_FLT_ROUNDS /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (d < 0) { + if (dval(d) < 0) { L--; - d += ds; - } + dval(d) += ds; + } #endif *s++ = '0' + (int)L; + if (!dval(d)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } if (i == ilim) { - d += d; - if (d > ds || (d == ds && L & 1)) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(d) += dval(d); + if (dval(d) > ds || dval(d) == ds && L & 1) { bump_up: - while (*--s == '9') + while(*--s == '9') if (s == s0) { k++; *s = '0'; break; - } + } ++*s++; - } + } break; + } } - if (!(d *= 10.)) - break; - } goto ret1; - } + } m2 = b2; m5 = b5; mhi = mlo = 0; if (leftright) { - if (mode < 2) { - i = + i = #ifndef Sudden_Underflow - denorm ? be + (Bias + (P-1) - 1 + 1) : + denorm ? be + (Bias + (P-1) - 1 + 1) : #endif #ifdef IBM - 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); #else - 1 + P - bbits; + 1 + P - bbits; #endif - } else { - j = ilim - 1; - if (m5 >= j) - m5 -= j; - else { - s5 += j -= m5; - b5 += j; - m5 = 0; - } - if ((i = ilim) < 0) { - m2 -= i; - i = 0; - } - } b2 += i; s2 += i; mhi = i2b(1); - } + } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; b2 -= i; m2 -= i; s2 -= i; - } + } if (b5 > 0) { if (leftright) { if (m5 > 0) { @@ -2279,30 +3087,35 @@ __bsd_dtoa Bfree(b); b = b1; } - if ( (j = b5 - m5) ) + if (j = b5 - m5) b = pow5mult(b, j); - } else + } + else b = pow5mult(b, b5); - } + } S = i2b(1); if (s5 > 0) S = pow5mult(S, s5); /* Check for special case that d is a normalized power of 2. */ - if (mode < 2) { + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && rounding == 1 +#endif + ) { if (!word1(d) && !(word0(d) & Bndry_mask) #ifndef Sudden_Underflow - && word0(d) & Exp_mask + && word0(d) & (Exp_mask & ~Exp_msk1) #endif ) { /* The special case */ b2 += Log2P; s2 += Log2P; spec_case = 1; - } else - spec_case = 0; - } + } + } /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. @@ -2312,10 +3125,10 @@ __bsd_dtoa * can do shifts and ors to compute the numerator for q. */ #ifdef Pack_32 - if ( (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) ) + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) i = 32 - i; #else - if ( (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) ) + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) i = 16 - i; #endif if (i > 4) { @@ -2323,12 +3136,13 @@ __bsd_dtoa b2 += i; m2 += i; s2 += i; - } else if (i < 4) { + } + else if (i < 4) { i += 28; b2 += i; m2 += i; s2 += i; - } + } if (b2 > 0) b = lshift(b, b2); if (s2 > 0) @@ -2340,20 +3154,20 @@ __bsd_dtoa if (leftright) mhi = multadd(mhi, 10, 0); ilim = ilim1; + } } - } - if (ilim <= 0 && mode > 2) { + if (ilim <= 0 && (mode == 3 || mode == 5)) { if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { /* no digits, fcvt style */ no_digits: k = -1 - ndigits; goto ret; - } + } one_digit: *s++ = '1'; k++; goto ret; - } + } if (leftright) { if (m2 > 0) mhi = lshift(mhi, m2); @@ -2367,9 +3181,9 @@ __bsd_dtoa mhi = Balloc(mhi->k); Bcopy(mhi, mlo); mhi = lshift(mhi, Log2P); - } + } - for (i = 1;;i++) { + for(i = 1;;i++) { dig = quorem(b,S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? @@ -2379,39 +3193,68 @@ __bsd_dtoa j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); #ifndef ROUND_BIASED - if (j1 == 0 && !mode && !(word1(d) & 1)) { + if (j1 == 0 && mode != 1 && !(word1(d) & 1) +#ifdef Honor_FLT_ROUNDS + && rounding >= 1 +#endif + ) { if (dig == '9') goto round_9_up; if (j > 0) dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif *s++ = dig; goto ret; - } + } #endif - if (j < 0 || (j == 0 && !mode + if (j < 0 || j == 0 && mode != 1 #ifndef ROUND_BIASED && !(word1(d) & 1) #endif - )) { + ) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { b = lshift(b, 1); j1 = cmp(b, S); - if ((j1 > 0 || (j1 == 0 && dig & 1)) + if ((j1 > 0 || j1 == 0 && dig & 1) && dig++ == '9') goto round_9_up; - } + } + accept_dig: *s++ = dig; goto ret; - } + } if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!rounding) + goto accept_dig; +#endif if (dig == '9') { /* possible if i == 1 */ round_9_up: *s++ = '9'; goto roundoff; - } + } *s++ = dig + 1; goto ret; - } + } +#ifdef Honor_FLT_ROUNDS + keep_dig: +#endif *s++ = dig; if (i == ilim) break; @@ -2421,52 +3264,76 @@ __bsd_dtoa else { mlo = multadd(mlo, 10, 0); mhi = multadd(mhi, 10, 0); + } } } - } else - for (i = 1;; i++) { + else + for(i = 1;; i++) { *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } if (i >= ilim) break; b = multadd(b, 10, 0); - } + } /* Round off last digit */ +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif b = lshift(b, 1); j = cmp(b, S); - if (j > 0 || (j == 0 && dig & 1)) { + if (j > 0 || j == 0 && dig & 1) { roundoff: - while (*--s == '9') + while(*--s == '9') if (s == s0) { k++; *s++ = '1'; goto ret; - } + } ++*s++; - } else { - while (*--s == '0'); + } + else { + trimzeros: + while(*--s == '0'); s++; - } + } ret: Bfree(S); if (mhi) { if (mlo && mlo != mhi) Bfree(mlo); Bfree(mhi); - } + } ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(d) = Exp_1 + (70 << Exp_shift); + word1(d) = 0; + dval(d) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif Bfree(b); - if (s == s0) { /* don't return empty string */ - *s++ = '0'; - k = 0; - } *s = 0; *decpt = k + 1; if (rve) *rve = s; return s0; } +#endif + #ifdef __cplusplus } #endif