***************************************************************/
/* 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
- */
+ 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
+ */
/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
*
#include <zend.h>
#include <unicode/utypes.h>
#include <unicode/ustdio.h>
+#include <zend_strtod.h>
+
+#ifdef ZTS
+#include <TSRM.h>
+#endif
+
+#include <stddef.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#if defined(__arm__) && !defined(__VFP_FP__)
/*
- * Although the CPU is little endian the FP has different
- * byte and word endianness. The byte order is still little endian
- * but the word order is big endian.
- */
+ * * Although the CPU is little endian the FP has different
+ * * byte and word endianness. The byte order is still little endian
+ * * but the word order is big endian.
+ * */
#define IEEE_BIG_ENDIAN
#undef IEEE_LITTLE_ENDIAN
#endif
#define IEEE_LITTLE_ENDIAN
#endif
-#define Long int32_t
-#define ULong uint32_t
+#define Long int32_t
+#define ULong uint32_t
#ifdef __cplusplus
#include "malloc.h"
#define DBL_MAX 1.7014118346046923e+38
#endif
+
#ifndef LONG_MAX
#define LONG_MAX 2147483647
#endif
#include "math.h"
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
+BEGIN_EXTERN_C()
#ifndef CONST
#ifdef KR_headers
#endif
#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + \
- defined(IBM) != 1
-Exactly one of IEEE_LITTLE_ENDIAN IEEE_BIG_ENDIAN, VAX, or
-IBM should be defined.
+ defined(IBM) != 1
+ Exactly one of IEEE_LITTLE_ENDIAN IEEE_BIG_ENDIAN, VAX, or
+ IBM should be defined.
#endif
-typedef union {
- double d;
- ULong ul[2];
-} _double;
+ typedef union {
+ double d;
+ ULong ul[2];
+ } _double;
#define value(x) ((x).d)
#ifdef IEEE_LITTLE_ENDIAN
#define word0(x) ((x).ul[1])
#endif
/* The following definition of Storeinc is appropriate for MIPS processors.
- * An alternative that might be better on some machines is
- * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
- */
+ * * An alternative that might be better on some machines is
+ * * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ * */
#if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__)
#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
-((unsigned short *)a)[0] = (unsigned short)c, a++)
+ ((unsigned short *)a)[0] = (unsigned short)c, a++)
#else
#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
-((unsigned short *)a)[1] = (unsigned short)c, a++)
+ ((unsigned short *)a)[1] = (unsigned short)c, a++)
#endif
/* #define P DBL_MANT_DIG */
#define Bias 65
#define Exp_1 0x41000000
#define Exp_11 0x41000000
-#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
+#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
#define Frac_mask 0xffffff
#define Frac_mask1 0xffffff
#define Bletch 4
#ifndef Just_16
/* 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.
- */
+ * * 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.
+ * */
#ifndef Pack_32
#define Pack_32
#endif
#define Kmax 15
- struct
-Bigint {
+struct Bigint {
struct Bigint *next;
int k, maxwds, sign, wds;
ULong x[1];
- };
+};
- typedef struct Bigint Bigint;
+typedef struct Bigint Bigint;
- static Bigint *freelist[Kmax+1];
+static Bigint *freelist[Kmax+1];
+static void destroy_freelist(void);
- static Bigint *
-Balloc
-#ifdef KR_headers
- (k) int k;
-#else
- (int k)
+#ifdef ZTS
+
+static MUTEX_T dtoa_mutex;
+static MUTEX_T pow5mult_mutex;
+
+#define _THREAD_PRIVATE_MUTEX_LOCK(x) tsrm_mutex_lock(x);
+#define _THREAD_PRIVATE_MUTEX_UNLOCK(x) tsrm_mutex_unlock(x);
+
+#else
+
+#define _THREAD_PRIVATE_MUTEX_LOCK(x)
+#define _THREAD_PRIVATE_MUTEX_UNLOCK(x)
+
+#endif /* ZTS */
+
+ZEND_API int zend_startup_strtod(void) /* {{{ */
+{
+#ifdef ZTS
+ dtoa_mutex = tsrm_mutex_alloc();
+ pow5mult_mutex = tsrm_mutex_alloc();
+#endif
+ return 1;
+}
+/* }}} */
+ZEND_API int zend_shutdown_strtod(void) /* {{{ */
+{
+#ifdef ZTS
+ tsrm_mutex_free(dtoa_mutex);
+ dtoa_mutex = NULL;
+
+ tsrm_mutex_free(pow5mult_mutex);
+ pow5mult_mutex = NULL;
#endif
+ destroy_freelist();
+ return 1;
+}
+/* }}} */
+
+static Bigint * Balloc(int k)
{
int x;
Bigint *rv;
+ _THREAD_PRIVATE_MUTEX_LOCK(dtoa_mutex);
if ((rv = freelist[k])) {
freelist[k] = rv->next;
- }
- else {
+ } else {
x = 1 << k;
rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
rv->k = k;
rv->maxwds = x;
- }
+ }
+ _THREAD_PRIVATE_MUTEX_UNLOCK(dtoa_mutex);
rv->sign = rv->wds = 0;
return rv;
- }
+}
- static void
-Bfree
-#ifdef KR_headers
- (v) Bigint *v;
-#else
- (Bigint *v)
-#endif
+static void Bfree(Bigint *v)
{
if (v) {
+ _THREAD_PRIVATE_MUTEX_LOCK(dtoa_mutex);
v->next = freelist[v->k];
freelist[v->k] = v;
- }
+ _THREAD_PRIVATE_MUTEX_UNLOCK(dtoa_mutex);
}
+}
#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
-y->wds*sizeof(Long) + 2*sizeof(int))
+ y->wds*sizeof(Long) + 2*sizeof(int))
- static Bigint *
-multadd
-#ifdef KR_headers
- (b, m, a) Bigint *b; int m, a;
-#else
- (Bigint *b, int m, int a) /* multiply by m and add a */
-#endif
+/* return value is only used as a simple string, so mis-aligned parts
+ * inside the Bigint are not at risk on strict align architectures
+ */
+static char * rv_alloc(int i) {
+ 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 (char *)(r+1);
+}
+
+
+static char * nrv_alloc(char *s, char **rve, int n)
+{
+ char *rv, *t;
+
+ t = rv = rv_alloc(n);
+ while((*t = *s++) !=0) {
+ t++;
+ }
+ if (rve) {
+ *rve = t;
+ }
+ return rv;
+}
+
+static Bigint * multadd(Bigint *b, int m, int a) /* multiply by m and add a */
{
int i, wds;
ULong *x, y;
a = (int)(y >> 16);
*x++ = y & 0xffff;
#endif
- }
- while(++i < wds);
+ }
+ while(++i < wds);
if (a) {
if (wds >= b->maxwds) {
b1 = Balloc(b->k+1);
Bcopy(b1, b);
Bfree(b);
b = b1;
- }
+ }
b->x[wds++] = a;
b->wds = wds;
- }
- return b;
}
-
- static Bigint *
-s2b
-#ifdef KR_headers
- (s, nd0, nd, y9) CONST char *s; int nd0, nd; ULong y9;
-#else
- (CONST char *s, int nd0, int nd, ULong y9)
-#endif
-{
- Bigint *b;
- int i, k;
- Long x, y;
-
- x = (nd + 8) / 9;
- for(k = 0, y = 1; x > y; y <<= 1, k++) ;
-#ifdef Pack_32
- b = Balloc(k);
- b->x[0] = y9;
- b->wds = 1;
-#else
- b = Balloc(k+1);
- b->x[0] = y9 & 0xffff;
- b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
-#endif
-
- i = 9;
- if (9 < nd0) {
- s += 9;
- do b = multadd(b, 10, *s++ - '0');
- while(++i < nd0);
- s++;
- }
- else
- s += 10;
- for(; i < nd; i++)
- b = multadd(b, 10, *s++ - '0');
return b;
- }
+}
- static int
-hi0bits
-#ifdef KR_headers
- (x) register ULong x;
-#else
- (register ULong x)
-#endif
+static int hi0bits(ULong x)
{
- register int k = 0;
+ int k = 0;
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))
+ if (!(x & 0x40000000)) {
return 32;
}
- return k;
}
+ return k;
+}
- static int
-lo0bits
-#ifdef KR_headers
- (y) ULong *y;
-#else
- (ULong *y)
-#endif
+static int lo0bits(ULong *y)
{
- register int k;
- register ULong x = *y;
+ int k;
+ ULong x = *y;
if (x & 7) {
- if (x & 1)
+ if (x & 1) {
return 0;
+ }
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 & 1)) {
return 32;
}
+ }
*y = x;
return k;
- }
+}
- static Bigint *
-i2b
-#ifdef KR_headers
- (i) int i;
-#else
- (int i)
-#endif
+static Bigint * i2b(int i)
{
Bigint *b;
b->x[0] = i;
b->wds = 1;
return b;
- }
+}
- static Bigint *
-mult
-#ifdef KR_headers
- (a, b) Bigint *a, *b;
-#else
- (Bigint *a, Bigint *b)
-#endif
+static Bigint * mult(Bigint *a, Bigint *b)
{
Bigint *c;
int k, wa, wb, wc;
c = a;
a = b;
b = c;
- }
+ }
k = a->k;
wa = a->wds;
wb = b->wds;
wc = wa + wb;
- if (wc > a->maxwds)
+ 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;
z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
carry = z2 >> 16;
Storeinc(xc, z2, z);
- }
- while(x < xae);
- *xc = carry;
}
+ while(x < xae);
+ *xc = carry;
+ }
if ((y = *xb >> 16)) {
x = xa;
xc = xc0;
Storeinc(xc, z, z2);
z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
carry = z2 >> 16;
- }
- while(x < xae);
- *xc = z2;
}
+ while(x < xae);
+ *xc = z2;
}
+ }
#else
for(; xb < xbe; xc0++) {
if (y = *xb++) {
z = *x++ * y + *xc + carry;
carry = z >> 16;
*xc++ = z & 0xffff;
- }
- while(x < xae);
- *xc = carry;
}
+ while(x < xae);
+ *xc = carry;
}
+ }
#endif
for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
c->wds = wc;
return c;
- }
+}
- static Bigint *p5s;
+static Bigint * s2b (CONST char *s, int nd0, int nd, ULong y9)
+{
+ Bigint *b;
+ int i, k;
+ Long x, y;
- static Bigint *
-pow5mult
-#ifdef KR_headers
- (b, k) Bigint *b; int k;
+ x = (nd + 8) / 9;
+ for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+ b = Balloc(k);
+ b->x[0] = y9;
+ b->wds = 1;
#else
- (Bigint *b, int k)
+ b = Balloc(k+1);
+ b->x[0] = y9 & 0xffff;
+ b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
#endif
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do b = multadd(b, 10, *s++ - '0');
+ while(++i < nd0);
+ s++;
+ } else {
+ s += 10;
+ }
+ for(; i < nd; i++) {
+ b = multadd(b, 10, *s++ - '0');
+ }
+ return b;
+}
+
+
+static Bigint *p5s;
+
+static Bigint * pow5mult(Bigint *b, int k)
{
Bigint *b1, *p5, *p51;
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))
+ if (!(k >>= 2)) {
return b;
+ }
if (!(p5 = p5s)) {
/* first time */
+ _THREAD_PRIVATE_MUTEX_LOCK(pow5mult_mutex);
p5 = p5s = i2b(625);
p5->next = 0;
- }
+ _THREAD_PRIVATE_MUTEX_UNLOCK(pow5mult_mutex);
+ }
for(;;) {
if (k & 1) {
b1 = mult(b, p5);
Bfree(b);
b = b1;
- }
- if (!(k >>= 1))
+ }
+ if (!(k >>= 1)) {
break;
+ }
if (!(p51 = p5->next)) {
- p51 = p5->next = mult(p5,p5);
- p51->next = 0;
+ _THREAD_PRIVATE_MUTEX_LOCK(pow5mult_mutex);
+ if (!(p51 = p5->next)) {
+ p51 = p5->next = mult(p5,p5);
+ p51->next = 0;
}
- p5 = p51;
+ _THREAD_PRIVATE_MUTEX_UNLOCK(pow5mult_mutex);
}
- return b;
+ p5 = p51;
}
+ return b;
+}
- static Bigint *
-lshift
-#ifdef KR_headers
- (b, k) Bigint *b; int k;
-#else
- (Bigint *b, int k)
-#endif
+
+static Bigint *lshift(Bigint *b, int k)
{
int i, k1, n, n1;
Bigint *b1;
#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;
#ifdef Pack_32
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;
do {
*x1++ = *x << k & 0xffff | z;
z = *x++ >> k1;
- }
- while(x < xe);
- if (*x1 = z)
+ }
+ while(x < xe);
+ if (*x1 = z) {
++n1;
}
+ }
#endif
else do
*x1++ = *x++;
- while(x < xe);
+ while(x < xe);
b1->wds = n1 - 1;
Bfree(b);
return b1;
- }
+}
- static int
-cmp
-#ifdef KR_headers
- (a, b) Bigint *a, *b;
-#else
- (Bigint *a, Bigint *b)
-#endif
+static int cmp(Bigint *a, Bigint *b)
{
ULong *xa, *xa0, *xb, *xb0;
int i, j;
return *xa < *xb ? -1 : 1;
if (xa <= xa0)
break;
- }
- return 0;
}
+ return 0;
+}
- static Bigint *
-diff
-#ifdef KR_headers
- (a, b) Bigint *a, *b;
-#else
- (Bigint *a, Bigint *b)
-#endif
+
+static Bigint * diff(Bigint *a, Bigint *b)
{
Bigint *c;
int i, wa, wb;
- Long borrow, y; /* We need signed shifts here. */
+ Long borrow, y; /* We need signed shifts here. */
ULong *xa, *xae, *xb, *xbe, *xc;
#ifdef Pack_32
Long z;
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;
wa = a->wds;
borrow = z >> 16;
Sign_Extend(borrow, z);
Storeinc(xc, z, y);
- }
- while(xb < xbe);
+ } while(xb < xbe);
while(xa < xae) {
y = (*xa & 0xffff) + borrow;
borrow = y >> 16;
borrow = z >> 16;
Sign_Extend(borrow, z);
Storeinc(xc, z, y);
- }
+ }
#else
do {
y = *xa++ - *xb++ + borrow;
borrow = y >> 16;
Sign_Extend(borrow, y);
*xc++ = y & 0xffff;
- }
- while(xb < xbe);
+ } while(xb < xbe);
while(xa < xae) {
y = *xa++ + borrow;
borrow = y >> 16;
Sign_Extend(borrow, y);
*xc++ = y & 0xffff;
- }
+ }
#endif
- while(!*--xc)
+ while(!*--xc) {
wa--;
+ }
c->wds = wa;
return c;
- }
+}
- static double
-ulp
-#ifdef KR_headers
- (_x) double _x;
-#else
- (double _x)
-#endif
+static double ulp (double _x)
{
_double x;
register Long L;
word0(a) = L;
word1(a) = 0;
#ifndef Sudden_Underflow
- }
+ }
else {
L = -L >> Exp_shift;
if (L < Exp_shift) {
word0(a) = 0x80000 >> L;
word1(a) = 0;
- }
+ }
else {
word0(a) = 0;
L -= Exp_shift;
word1(a) = L >= 31 ? 1 : 1 << (31 - L);
- }
}
+ }
#endif
return value(a);
- }
+}
- static double
+static double
b2d
#ifdef KR_headers
- (a, e) Bigint *a; int *e;
+(a, e) Bigint *a; int *e;
#else
- (Bigint *a, int *e)
+(Bigint *a, int *e)
#endif
{
ULong *xa, *xa0, w, y, z;
w = xa > xa0 ? *--xa : 0;
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);
y = xa > xa0 ? *--xa : 0;
d1 = z << k | y >> (32 - k);
- }
+ }
else {
d0 = Exp_1 | y;
d1 = z;
- }
+ }
#else
if (k < Ebits + 16) {
z = xa > xa0 ? *--xa : 0;
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;
y = xa > xa0 ? *--xa : 0;
d1 = w << k + 16 | y << k;
#endif
- ret_d:
+ret_d:
#ifdef VAX
word0(d) = d0 >> 16 | d0 << 16;
word1(d) = d1 >> 16 | d1 << 16;
#undef d1
#endif
return value(d);
- }
+}
- static Bigint *
-d2b
-#ifdef KR_headers
- (_d, e, bits) double d; int *e, *bits;
-#else
- (double _d, int *e, int *bits)
-#endif
+
+static Bigint * d2b(double _d, int *e, int *bits)
{
Bigint *b;
int de, i, k;
x = b->x;
z = d0 & Frac_mask;
- d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
#ifdef Sudden_Underflow
de = (int)(d0 >> Exp_shift);
#ifndef IBM
#ifdef Pack_32
if ((y = d1)) {
if ((k = lo0bits(&y))) {
- x[0] = y | z << (32 - k);
+ x[0] = y | (z << (32 - k));
z >>= k;
- }
- else
+ } else {
x[0] = y;
- i = b->wds = (x[1] = z) ? 2 : 1;
}
- else {
+ i = b->wds = (x[1] = z) ? 2 : 1;
+ } else {
#ifdef DEBUG
if (!z)
Bug("Zero passed to d2b");
x[0] = z;
i = b->wds = 1;
k += 32;
- }
+ }
#else
if (y = d1) {
- if (k = lo0bits(&y))
+ if (k = lo0bits(&y)) {
if (k >= 16) {
x[0] = y | z << 32 - k & 0xffff;
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 {
+ }
+ } 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");
if (k >= 16) {
x[0] = z;
i = 0;
- }
- else {
+ } else {
x[0] = z & 0xffff;
x[1] = z >> 16;
i = 1;
- }
- k += 32;
}
+ k += 32;
+ }
while(!x[i])
--i;
b->wds = i + 1;
*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
- static double
-ratio
-#ifdef KR_headers
- (a, b) Bigint *a, *b;
-#else
- (Bigint *a, Bigint *b)
-#endif
+
+static double ratio (Bigint *a, Bigint *b)
{
_double da, db;
int k, ka, kb;
#ifdef IBM
if (k > 0) {
word0(da) += (k >> 2)*Exp_msk1;
- if (k &= 3)
+ if (k &= 3) {
da *= 1 << k;
}
- else {
+ } else {
k = -k;
word0(db) += (k >> 2)*Exp_msk1;
if (k &= 3)
db *= 1 << k;
- }
+ }
#else
- if (k > 0)
+ if (k > 0) {
word0(da) += k*Exp_msk1;
- else {
+ } else {
k = -k;
word0(db) += k*Exp_msk1;
- }
+ }
#endif
return value(da) / value(db);
- }
+}
static CONST double
tens[] = {
- 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
- 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
- 1e20, 1e21, 1e22
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
#ifdef VAX
, 1e23, 1e24
#endif
- };
+};
#ifdef IEEE_Arith
static CONST double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
#endif
#endif
-ZEND_API double
-zend_strtod
-#ifdef KR_headers
- (s00, se) CONST char *s00; char **se;
+
+static int quorem(Bigint *b, Bigint *S)
+{
+ int n;
+ Long borrow, y;
+ ULong carry, q, ys;
+ ULong *bx, *bxe, *sx, *sxe;
+#ifdef Pack_32
+ Long z;
+ ULong si, zs;
+#endif
+
+ n = S->wds;
+#ifdef DEBUG
+ /*debug*/ if (b->wds > n)
+ /*debug*/ Bug("oversize b in quorem");
+#endif
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+#ifdef DEBUG
+ /*debug*/ if (q > 9)
+ /*debug*/ Bug("oversized quotient in quorem");
+#endif
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#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);
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ * q + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ *bx++ = y & 0xffff;
+#endif
+ }
+ while(sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#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);
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ *bx++ = y & 0xffff;
+#endif
+ }
+ while(sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+}
+
+static void destroy_freelist(void)
+{
+ int i;
+ Bigint *tmp;
+
+ _THREAD_PRIVATE_MUTEX_LOCK(dtoa_mutex);
+ for (i = 0; i <= Kmax; i++) {
+ Bigint **listp = &freelist[i];
+ while ((tmp = *listp) != NULL) {
+ *listp = tmp->next;
+ free(tmp);
+ }
+ freelist[i] = NULL;
+ }
+ _THREAD_PRIVATE_MUTEX_UNLOCK(dtoa_mutex);
+
+}
+
+
+ZEND_API void zend_freedtoa(char *s)
+{
+ Bigint *b = (Bigint *)((int *)s - 1);
+ b->maxwds = 1 << (b->k = *(int*)b);
+ Bfree(b);
+}
+
+/* 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].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * 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
+ * calculation.
+ */
+
+ZEND_API char * zend_dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ 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).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+ j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick;
+ Long L;
+#ifndef Sudden_Underflow
+ int denorm;
+ ULong x;
+#endif
+ Bigint *b, *b1, *delta, *mlo, *mhi, *S, *tmp;
+ double ds;
+ char *s, *s0;
+ _double d, d2, eps;
+
+ value(d) = _d;
+
+ 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;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+ if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+ if (word0(d) == 0x8000)
+#endif
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+#ifdef IEEE_Arith
+ if (!word1(d) && !(word0(d) & 0xfffff))
+ return nrv_alloc("Infinity", rve, 8);
+#endif
+ return nrv_alloc("NaN", rve, 3);
+ }
+#endif
+#ifdef IBM
+ value(d) += 0; /* normalize */
+#endif
+ if (!value(d)) {
+ *decpt = 1;
+ return nrv_alloc("0", rve, 1);
+ }
+
+ b = d2b(value(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)))) {
+#endif
+ value(d2) = value(d);
+ word0(d2) &= Frac_mask1;
+ word0(d2) |= Exp_11;
+#ifdef IBM
+ if (j = 11 - hi0bits(word0(d2) & Frac_mask))
+ value(d2) /= 1 << j;
+#endif
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifdef IBM
+ i <<= 2;
+ i += j;
+#endif
+#ifndef Sudden_Underflow
+ denorm = 0;
+ }
+ 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));
+ value(d2) = x;
+ word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P-1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ ds = (value(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 (value(d) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+ try_quick = 1;
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ switch(mode) {
+ case 0:
+ case 1:
+ ilim = ilim1 = -1;
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ s = s0 = rv_alloc(i);
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ value(d2) = value(d);
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ value(d) /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for(; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ value(d) /= ds;
+ }
+ else if ((j1 = -k)) {
+ value(d) *= tens[j1 & 0xf];
+ for(j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ value(d) *= bigtens[i];
+ }
+ }
+ if (k_check && value(d) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ value(d) *= 10.;
+ ieps++;
+ }
+ value(eps) = ieps*value(d) + 7.;
+ word0(eps) -= (P-1)*Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ value(d) -= 5.;
+ if (value(d) > value(eps))
+ goto one_digit;
+ if (value(d) < -value(eps))
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ value(eps) = 0.5/tens[ilim-1] - value(eps);
+ for(i = 0;;) {
+ L = value(d);
+ value(d) -= L;
+ *s++ = '0' + (int)L;
+ if (value(d) < value(eps))
+ goto ret1;
+ if (1. - value(d) < value(eps))
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ value(eps) *= 10.;
+ value(d) *= 10.;
+ }
+ }
+ else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ value(eps) *= tens[ilim-1];
+ for(i = 1;; i++, value(d) *= 10.) {
+ L = value(d);
+ value(d) -= L;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (value(d) > 0.5 + value(eps))
+ goto bump_up;
+ else if (value(d) < 0.5 - value(eps)) {
+ while(*--s == '0');
+ s++;
+ goto ret1;
+ }
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+fast_failed:
+ s = s0;
+ value(d) = value(d2);
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || value(d) <= 5*ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for(i = 1;; i++) {
+ L = value(d) / ds;
+ value(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (value(d) < 0) {
+ L--;
+ value(d) += ds;
+ }
+#endif
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ value(d) += value(d);
+ if (value(d) > ds || (value(d) == ds && (L & 1))) {
+bump_up:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ if (!(value(d) *= 10.))
+ break;
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ mhi = mlo = 0;
+ if (leftright) {
+ if (mode < 2) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+ 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+ 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) {
+ mhi = pow5mult(mhi, m5);
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ }
+ if ((j = b5 - m5)) {
+ b = pow5mult(b, j);
+ }
+ } 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) {
+ if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(d) & Exp_mask
+#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.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * 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))
+ i = 32 - i;
#else
- (CONST char *s00, char **se)
+ if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf))
+ i = 16 - i;
+#endif
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ if (b2 > 0)
+ b = lshift(b, b2);
+ if (s2 > 0)
+ S = lshift(S, s2);
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (leftright)
+ mhi = multadd(mhi, 10, 0);
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && mode > 2) {
+ 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);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ }
+
+ for(i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+#ifndef ROUND_BIASED
+ if (j1 == 0 && !mode && !(word1(d) & 1)) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+ *s++ = dig;
+ goto ret;
+ }
#endif
+ if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+ && !(word1(d) & 1)
+#endif
+ )) {
+ if (j1 > 0) {
+ b = lshift(b, 1);
+ j1 = cmp(b, S);
+ if ((j1 > 0 || (j1 == 0 && (dig & 1)))
+ && dig++ == '9')
+ goto round_9_up;
+ }
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+ if (dig == '9') { /* possible if i == 1 */
+round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (mlo == mhi)
+ mlo = mhi = multadd(mhi, 10, 0);
+ else {
+ mlo = multadd(mlo, 10, 0);
+ mhi = multadd(mhi, 10, 0);
+ }
+ }
+ }
+ else
+ for(i = 1;; i++) {
+ *s++ = dig = quorem(b,S) + '0';
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ }
+
+ /* Round off last digit */
+
+ b = lshift(b, 1);
+ j = cmp(b, S);
+ if (j > 0 || (j == 0 && (dig & 1))) {
+roundoff:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ }
+ else {
+ while(*--s == '0');
+ s++;
+ }
+ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ret1:
+
+ _THREAD_PRIVATE_MUTEX_LOCK(pow5mult_mutex);
+ while (p5s) {
+ tmp = p5s;
+ p5s = p5s->next;
+ free(tmp);
+ }
+ _THREAD_PRIVATE_MUTEX_UNLOCK(pow5mult_mutex);
+
+ 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;
+}
+
+ZEND_API double zend_strtod (CONST char *s00, char **se)
{
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
- e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+ e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
CONST char *s, *s0, *s1;
double aadj, aadj1, adj;
_double rv, rv0;
while(*++s == '0') ;
if (!*s)
goto ret;
- }
+ }
s0 = s;
y = z = 0;
for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
nf += nz;
nz = 0;
goto have_dig;
- }
- goto dig_done;
}
+ goto dig_done;
+ }
for(; c >= '0' && c <= '9'; c = *++s) {
- have_dig:
+have_dig:
nz++;
if (c -= '0') {
nf += nz;
else if (nd <= DBL_DIG + 1)
z = 10*z + c;
nz = 0;
- }
}
}
- dig_done:
+ }
+dig_done:
e = 0;
if (c == 'e' || c == 'E') {
if (!nd && !nz && !nz0) {
s = s00;
goto ret;
- }
+ }
s00 = s;
esign = 0;
switch(c = *++s) {
esign = 1;
case '+':
c = *++s;
- }
+ }
if (c >= '0' && c <= '9') {
while(c == '0')
c = *++s;
e = (int)L;
if (esign)
e = -e;
- }
+ }
else
e = 0;
- }
+ }
else
s = s00;
- }
+ }
if (!nd) {
if (!nz && !nz0)
s = s00;
goto ret;
- }
+ }
e1 = e -= nf;
/* Now we have nd0 digits, starting at s0, followed by a
bd0 = 0;
if (nd <= DBL_DIG
#ifndef RND_PRODQUOT
- && FLT_ROUNDS == 1
+ && FLT_ROUNDS == 1
#endif
- ) {
+ ) {
if (!e)
goto ret;
if (e > 0) {
goto vax_ovfl_check;
#else
/* value(rv) = */ rounded_product(value(rv),
- tens[e]);
+ tens[e]);
goto ret;
#endif
- }
+ }
i = DBL_DIG - nd;
if (e <= Ten_pmax + i) {
/* A fancier test would sometimes let us do
/* VAX exponent range is so narrow we must
* worry about overflow here...
*/
- vax_ovfl_check:
+vax_ovfl_check:
word0(rv) -= P*Exp_msk1;
/* value(rv) = */ rounded_product(value(rv),
- tens[e]);
+ tens[e]);
if ((word0(rv) & Exp_mask)
- > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+ > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
goto ovfl;
word0(rv) += P*Exp_msk1;
#else
/* value(rv) = */ rounded_product(value(rv),
- tens[e]);
+ tens[e]);
#endif
goto ret;
- }
}
+ }
#ifndef Inaccurate_Divide
else if (e >= -Ten_pmax) {
/* value(rv) = */ rounded_quotient(value(rv),
- tens[-e]);
+ tens[-e]);
goto ret;
- }
-#endif
}
+#endif
+ }
e1 += nd - k;
/* Get starting approximation = rv * 10**e1 */
value(rv) *= tens[i];
if (e1 &= ~15) {
if (e1 > DBL_MAX_10_EXP) {
- ovfl:
+ovfl:
errno = ERANGE;
#ifndef Bad_float_h
value(rv) = HUGE_VAL;
if (bd0)
goto retfree;
goto ret;
- }
+ }
if (e1 >>= 4) {
for(j = 0; e1 > 1; j++, e1 >>= 1)
if (e1 & 1)
value(rv) *= bigtens[j];
- /* The last multiplication could overflow. */
+ /* The last multiplication could overflow. */
word0(rv) -= P*Exp_msk1;
value(rv) *= bigtens[j];
if ((z = word0(rv) & Exp_mask)
- > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+ > 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) {
e1 = -e1;
if ((i = e1 & 15))
value(rv) = 2.*value(rv0);
value(rv) *= tinytens[j];
if (!value(rv)) {
- undfl:
+undfl:
value(rv) = 0.;
errno = ERANGE;
if (bd0)
goto retfree;
goto ret;
- }
+ }
word0(rv) = Tiny0;
word1(rv) = Tiny1;
/* The refinement below will clean
* this approximation up.
*/
- }
}
}
+ }
/* Now the hard part -- adjusting rv to the correct value.*/
if (e >= 0) {
bb2 = bb5 = 0;
bd2 = bd5 = e;
- }
+ }
else {
bb2 = bb5 = -e;
bd2 = bd5 = 0;
- }
+ }
if (bbe >= 0)
bb2 += bbe;
else
bb2 -= i;
bd2 -= i;
bs2 -= i;
- }
+ }
if (bb5 > 0) {
bs = pow5mult(bs, bb5);
bb1 = mult(bs, bb);
Bfree(bb);
bb = bb1;
- }
+ }
if (bb2 > 0)
bb = lshift(bb, bb2);
if (bd5 > 0)
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) == 0xffffffff) {
/*boundary case -- increment exponent*/
word0(rv) = (word0(rv) & Exp_mask)
+ Exp_msk1
;
word1(rv) = 0;
break;
- }
}
+ }
else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
- drop_down:
+drop_down:
/* boundary case -- decrement exponent */
#ifdef Sudden_Underflow
L = word0(rv) & Exp_mask;
#ifdef IBM
if (L < Exp_msk1)
#else
- if (L <= Exp_msk1)
+ if (L <= Exp_msk1)
#endif
- goto undfl;
+ goto undfl;
L -= Exp_msk1;
#else
L = (word0(rv) & Exp_mask) - Exp_msk1;
#else
break;
#endif
- }
+ }
#ifndef ROUND_BIASED
if (!(word1(rv) & LSB))
break;
if (!value(rv))
goto undfl;
#endif
- }
+ }
#endif
break;
- }
+ }
if ((aadj = ratio(delta, bs)) <= 2.) {
if (dsign)
aadj = aadj1 = 1.;
#endif
aadj = 1.;
aadj1 = -1.;
- }
+ }
else {
/* special case -- power of FLT_RADIX to be */
/* rounded down... */
else
aadj *= 0.5;
aadj1 = -aadj;
- }
}
+ }
else {
aadj *= 0.5;
aadj1 = dsign ? aadj : -aadj;
case 0: /* towards 0 */
case 3: /* towards -infinity */
aadj1 += 0.5;
- }
+ }
#else
if (FLT_ROUNDS == 0)
aadj1 += 0.5;
#endif
- }
+ }
y = word0(rv) & Exp_mask;
/* Check for overflow */
word0(rv) = Big0;
word1(rv) = Big1;
goto cont;
- }
+ }
else
word0(rv) += P*Exp_msk1;
- }
+ }
else {
#ifdef Sudden_Underflow
if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
#ifdef IBM
if ((word0(rv) & Exp_mask) < P*Exp_msk1)
#else
- if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+ 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;
+ if (word0(rv0) == Tiny0
+ && word1(rv0) == Tiny1)
+ goto undfl;
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ goto cont;
}
- else
- word0(rv) -= P*Exp_msk1;
- }
+ else
+ word0(rv) -= P*Exp_msk1;
+ }
else {
adj = aadj1 * ulp(value(rv));
value(rv) += adj;
- }
+ }
#else
/* Compute adj so that the IEEE rounding rules will
* correctly round rv + adj in some half-way cases.
aadj1 = (double)(int)(aadj + 0.5);
if (!dsign)
aadj1 = -aadj1;
- }
+ }
adj = aadj1 * ulp(value(rv));
value(rv) += adj;
#endif
- }
+ }
z = word0(rv) & Exp_mask;
if (y == z) {
/* Can we stop now? */
if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
if (aadj < .4999999 || aadj > .5000001)
break;
- }
+ }
else if (aadj < .4999999/FLT_RADIX)
break;
- }
- cont:
+ }
+cont:
Bfree(bb);
Bfree(bd);
Bfree(bs);
Bfree(delta);
- }
- retfree:
+ }
+retfree:
Bfree(bb);
Bfree(bd);
Bfree(bs);
Bfree(bd0);
Bfree(delta);
- ret:
+ret:
if (se)
*se = (char *)s;
result = sign ? -value(rv) : value(rv);
- for (i = 0; i <= Kmax; i++) {
- Bigint **listp = &freelist[i];
- while ((tmp = *listp) != NULL) {
- *listp = tmp->next;
- free(tmp);
- }
- freelist[i] = NULL;
- }
-
+ _THREAD_PRIVATE_MUTEX_LOCK(pow5mult_mutex);
while (p5s) {
tmp = p5s;
p5s = p5s->next;
free(tmp);
}
+ _THREAD_PRIVATE_MUTEX_UNLOCK(pow5mult_mutex);
return result;
- }
+}
/* UTODO: someone can reimplement this using the code above, if they really want to. */
ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr)
return 0;
}
}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
/* $Id$ */
+
+#include "php.h"
+
+#include <zend_strtod.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+/*
+ * Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad)
+{
+ register char *s = NULL;
+ char *p, *rve, c;
+ size_t siz;
+
+ if (ndigit < 0) {
+ siz = -ndigit + 1;
+ } else {
+ siz = ndigit + 1;
+ }
+
+ /* __dtoa() doesn't allocate space for 0 so we do it by hand */
+ if (value == 0.0) {
+ *decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
+ *sign = 0;
+ if ((rve = s = (char *)malloc(ndigit?siz:2)) == NULL)
+ return(NULL);
+ *rve++ = '0';
+ *rve = '\0';
+ if (!ndigit) {
+ return(s);
+ }
+ } else {
+ p = zend_dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
+ if (*decpt == 9999) {
+ /* Infinity or Nan, convert to inf or nan like printf */
+ *decpt = 0;
+ c = *p;
+ zend_freedtoa(p);
+ return(c == 'I' ? "inf" : "nan");
+ }
+ /* Make a local copy and adjust rve to be in terms of s */
+ if (pad && fmode)
+ siz += *decpt;
+ if ((s = (char *)malloc(siz+1)) == NULL) {
+ zend_freedtoa(p);
+ return(NULL);
+ }
+ (void) strlcpy(s, p, siz);
+ rve = s + (rve - p);
+ zend_freedtoa(p);
+ }
+
+ /* Add trailing zeros */
+ if (pad) {
+ siz -= rve - s;
+ while (--siz)
+ *rve++ = '0';
+ *rve = '\0';
+ }
+
+ return(s);
+}
+
+char *bsd_ecvt(double value, int ndigit, int *decpt, int *sign)
+{
+ return(__cvt(value, ndigit, decpt, sign, 0, 1));
+}
+
+char *bsd_fcvt(double value, int ndigit, int *decpt, int *sign)
+{
+ return(__cvt(value, ndigit, decpt, sign, 1, 1));
+}
+
+char *bsd_gcvt(double value, int ndigit, char *buf)
+{
+ char *digits, *dst, *src;
+ int i, decpt, sign;
+ struct lconv *lconv;
+
+ lconv = localeconv();
+
+ digits = zend_dtoa(value, 2, ndigit, &decpt, &sign, NULL);
+ if (decpt == 9999) {
+ /*
+ * Infinity or NaN, convert to inf or nan with sign.
+ * We assume the buffer is at least ndigit long.
+ */
+ snprintf(buf, ndigit + 1, "%s%s", sign ? "-" : "",
+ *digits == 'I' ? "inf" : "nan");
+ zend_freedtoa(digits);
+ return (buf);
+ }
+
+ dst = buf;
+ if (sign)
+ *dst++ = '-';
+
+ for (i = 0; i < ndigit && digits[i] != '\0'; i++);
+
+ if ((decpt >= 0 && decpt - i > 4)
+ || (decpt < 0 && decpt < -3)) { /* use E-style */
+ /* exponential format (e.g. 1.2345e+13) */
+ if (--decpt < 0) {
+ sign = 1;
+ decpt = -decpt;
+ } else
+ sign = 0;
+ src = digits;
+ *dst++ = *src++;
+ *dst++ = *lconv->decimal_point;
+ if (*src == '\0') {
+ *dst++ = '0';
+ } else {
+ do {
+ *dst++ = *src++;
+ } while (*src != '\0');
+ }
+ *dst++ = 'e';
+ if (sign)
+ *dst++ = '-';
+ else
+ *dst++ = '+';
+ if (decpt < 10) {
+ *dst++ = '0' + decpt;
+ *dst = '\0';
+ } else {
+ /* XXX - optimize */
+ for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
+ continue;
+ dst[i + 1] = '\0';
+ while (decpt != 0) {
+ dst[i--] = '0' + decpt % 10;
+ decpt /= 10;
+ }
+ }
+ } else if (decpt < 0) {
+ /* standard format 0. */
+ *dst++ = '0'; /* zero before decimal point */
+ *dst++ = *lconv->decimal_point;
+ do {
+ *dst++ = '0';
+ } while (++decpt < 0);
+ src = digits;
+ while (*src != '\0') {
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+ } else {
+ /* standard format */
+ for (i = 0, src = digits; i < decpt; i++) {
+ if (*src != '\0')
+ *dst++ = *src++;
+ else
+ *dst++ = '0';
+ }
+ if (*src != '\0') {
+ if (src == digits)
+ *dst++ = '0'; /* zero before decimal point */
+ *dst++ = *lconv->decimal_point;
+ for (i = decpt; digits[i] != '\0'; i++) {
+ *dst++ = digits[i];
+ }
+ }
+ *dst = '\0';
+ }
+ zend_freedtoa(digits);
+ return (buf);
+}
+
+
/* ====================================================================
* Copyright (c) 1995-1998 The Apache Group. All rights reserved.
*
* <panos@alumni.cs.colorado.edu> for xinetd.
*/
-#include "php.h"
-
-#include <stddef.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
-#include <math.h>
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-
#define FALSE 0
#define TRUE 1
#define NUL '\0'
boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
{
register char *s = buf;
- register char *p;
+ register char *p, *p_orig;
int decimal_point;
- char buf1[NDIG];
+
+ if (precision >= NDIG - 1) {
+ precision = NDIG - 2;
+ }
if (format == 'f')
- p = ap_php_fcvt(num, precision, &decimal_point, is_negative, buf1);
+ p_orig = p = bsd_fcvt(num, precision, &decimal_point, is_negative);
else /* either e or E format */
- p = ap_php_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
+ p_orig = p = bsd_ecvt(num, precision + 1, &decimal_point, is_negative);
/*
* Check for Infinity and NaN
*len = strlen(p);
memcpy(buf, p, *len + 1);
*is_negative = FALSE;
+ free(p_orig);
return (buf);
}
if (format == 'f') {
if (decimal_point <= 0) {
- *s++ = '0';
- if (precision > 0) {
- *s++ = '.';
- while (decimal_point++ < 0)
- *s++ = '0';
- } else if (add_dp) {
- *s++ = '.';
+ if (num != 0 || precision > 0) {
+ *s++ = '0';
+ if (precision > 0) {
+ *s++ = '.';
+ while (decimal_point++ < 0)
+ *s++ = '0';
+ } else if (add_dp) {
+ *s++ = '.';
+ }
}
} else {
int addz = decimal_point >= NDIG ? decimal_point - NDIG + 1 : 0;
/*
* Make sure the exponent has at least 2 digits
*/
- if (t_len == 1)
- *s++ = '0';
while (t_len--)
*s++ = *p++;
} else {
*s++ = '+';
*s++ = '0';
- *s++ = '0';
}
}
*len = s - buf;
+ free(p_orig);
return (buf);
}
-
/*
* Convert num to a base X number where X is a power of 2. nbits determines X.
* For example, if nbits is 3, we do base 8 conversion
return (p);
}
-/*
- * cvt.c - IEEE floating point formatting routines for FreeBSD
- * from GNU libc-4.6.27
- */
-
-/*
- * ap_php_ecvt converts to decimal
- * the number of digits is specified by ndigit
- * decpt is set to the position of the decimal point
- * sign is set to 0 for positive, 1 for negative
- */
-
-
-char * ap_php_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
-{
- register int r2;
- int mvl;
- double fi, fj;
- register char *p, *p1;
-
- if (ndigits >= NDIG - 1)
- ndigits = NDIG - 2;
- r2 = 0;
- *sign = 0;
- p = &buf[0];
- if (arg < 0) {
- *sign = 1;
- arg = -arg;
- }
- arg = modf(arg, &fi);
- p1 = &buf[NDIG];
- /*
- * Do integer part
- */
- if (fi != 0) {
- while (fi != 0) {
- fj = modf(fi / 10, &fi);
- if (p1 <= &buf[0]) {
- mvl = NDIG - ndigits;
- if (ndigits > 0) {
- memmove(&buf[mvl], &buf[0], NDIG-mvl-1);
- }
- p1 += mvl;
- }
- *--p1 = (int) ((fj + .03) * 10) + '0';
- r2++;
- }
- while (p1 < &buf[NDIG]) {
- *p++ = *p1++;
- }
- } else if (arg > 0) {
- while ((fj = arg * 10) < 1) {
- if (!eflag && (r2 * -1) < ndigits) {
- break;
- }
- arg = fj;
- r2--;
- }
- }
- p1 = &buf[ndigits];
- if (eflag == 0)
- p1 += r2;
- *decpt = r2;
- if (p1 < &buf[0]) {
- buf[0] = '\0';
- return (buf);
- }
- if (p <= p1 && p < &buf[NDIG]) {
- arg = modf(arg * 10, &fj);
- if ((int)fj==10) {
- *p++ = '1';
- fj = 0;
- *decpt = ++r2;
- }
- while (p <= p1 && p < &buf[NDIG]) {
- *p++ = (int) fj + '0';
- arg = modf(arg * 10, &fj);
- }
- }
- if (p1 >= &buf[NDIG]) {
- buf[NDIG - 1] = '\0';
- return (buf);
- }
- p = p1;
- *p1 += 5;
- while (*p1 > '9') {
- *p1 = '0';
- if (p1 > buf)
- ++ * --p1;
- else {
- *p1 = '1';
- (*decpt)++;
- if (eflag == 0) {
- if (p > buf)
- *p = '0';
- p++;
- }
- }
- }
- *p = '\0';
- return (buf);
-}
-
-char * ap_php_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
-{
- return (ap_php_cvt(arg, ndigits, decpt, sign, 1, buf));
-}
-
-char * ap_php_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
-{
- return (ap_php_cvt(arg, ndigits, decpt, sign, 0, buf));
-}
-
-/*
- * ap_php_gcvt - Floating output conversion to
- * minimal length string
- */
-
-char * ap_php_gcvt(double number, int ndigit, char *buf, boolean_e altform)
-{
- int sign, decpt;
- register char *p1, *p2;
- register int i;
- char buf1[NDIG];
-
- if (ndigit >= NDIG - 1) {
- ndigit = NDIG - 2;
- }
-
- p1 = ap_php_ecvt(number, ndigit, &decpt, &sign, buf1);
- p2 = buf;
- if (sign)
- *p2++ = '-';
- for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
- ndigit--;
- if ((decpt >= 0 && decpt - ndigit > 4)
- || (decpt < 0 && decpt < -3)) { /* use E-style */
- decpt--;
- *p2++ = *p1++;
- *p2++ = '.';
- for (i = 1; i < ndigit; i++)
- *p2++ = *p1++;
- if (*(p2 - 1) == '.') {
- *p2++ = '0';
- }
- *p2++ = 'e';
- if (decpt < 0) {
- decpt = -decpt;
- *p2++ = '-';
- } else
- *p2++ = '+';
- if (decpt / 100 > 0)
- *p2++ = decpt / 100 + '0';
- if (decpt / 10 > 0)
- *p2++ = (decpt % 100) / 10 + '0';
- *p2++ = decpt % 10 + '0';
- } else {
- if (decpt <= 0) {
- if (*p1 != '0') {
- *p2++ = '0';
- *p2++ = '.';
- }
- while (decpt < 0) {
- decpt++;
- *p2++ = '0';
- }
- }
- for (i = 1; i <= ndigit; i++) {
- *p2++ = *p1++;
- if (i == decpt)
- *p2++ = '.';
- }
- if (ndigit < decpt) {
- while (ndigit++ < decpt)
- *p2++ = '0';
- *p2++ = '.';
- }
- }
- if (p2[-1] == '.' && !altform)
- p2--;
- *p2 = '\0';
- return (buf);
-}
/*
* NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
pad_char = ' ';
break;
-
+
case 'f':
case 'e':
case 'E':
/*
* * We use &num_buf[ 1 ], so that we have room for the sign
*/
- s = ap_php_gcvt(fp_num, precision, &num_buf[1],
- alternate_form);
+ s = bsd_gcvt(fp_num, precision, &num_buf[1]);
if (*s == '-')
prefix_char = *s++;
else if (print_sign)