FreeWRL

 view release on metacpan or  search on metacpan

JS/js/prdtoa.c  view on Meta::CPAN

			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 (int)q;
}

/* 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.
 */

static PRBool
PR_dtoa(double d, int mode, int ndigits,
	int *decpt, int *sign, char **rve, char *buf, size_t bufsize)
{
	/*	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.
	*/

	int32 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
	int32 denorm;
	ULong x;
#endif
	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
	double d2, ds, eps;
	char *s, *s0;
	Bigint *result = 0;
	static int32 result_k;
	PRBool retval;
        size_t strsize;

#ifdef JS_THREADSAFE
	if (!initialized) InitDtoa();
#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;

#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;
				s =
#ifdef IEEE_Arith
					!word1(d) && !(word0(d) & 0xfffff) ? "Infinity" :
#endif
					"NaN";
				if ((s[0] == 'I' && bufsize < 9) || (s[0] == 'N' && bufsize < 4)) {
					PR_ASSERT(PR_FALSE);
/* 					PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); */
					return PR_FALSE;
				}
				strcpy(buf, s);
				if (rve) {
					*rve =
#ifdef IEEE_Arith
						buf[3] ? buf + 8 :
#endif
					buf + 3;
					PR_ASSERT(**rve == '\0');
                                }
				return PR_TRUE;
			}
#endif
#ifdef IBM
	d += 0; /* normalize */
#endif
	if (!d) {
		*decpt = 1;
		if (bufsize < 2) {
			PR_ASSERT(PR_FALSE);
/* 			PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); */
			return PR_FALSE;
		}
		buf[0] = '0'; buf[1] = '\0';  /* copy "0" to buffer */
		if (rve) {
			*rve = buf + 1;
			PR_ASSERT(**rve == '\0');
		}
		return PR_TRUE;
	}

	b = d2b(d, &be, &bbits);
#ifdef Sudden_Underflow
	i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
#else
	if ((i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) {
#endif
		d2 = d;
		word0(d2) &= Frac_mask1;
		word0(d2) |= Exp_11;
#ifdef IBM
		if (j = 11 - hi0bits(word0(d2) & Frac_mask))
			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.

JS/js/prdtoa.c  view on Meta::CPAN

ret1:
	Bfree(b);
	*s = 0;
	*decpt = k + 1;
	strsize = (s - s0) + 1;
	if (strsize <= bufsize) {
		retval = PR_TRUE;
		memcpy(buf, s0, strsize);
		if (rve) {
			*rve = buf + strsize - 1;
			PR_ASSERT(**rve == '\0');
		}
	} else {
		PR_ASSERT(PR_FALSE);
/* 		PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); */
		retval = PR_FALSE;
	}

	/* cleanup */
	result->k = result_k;
	result->maxwds = 1 << result_k;
	Bfree(result);

	return retval;
}

/*
** conversion routines for floating point
** prcsn - number of digits of precision to generate floating
** point value.
** This should be reparameterized so that you can send in a
**   prcn for the positive and negative ranges.  For now, 
**   conform to the ECMA JavaScript spec which says numbers
**   less than 1e-6 are in scientific notation.
** Also, the ECMA spec says that there should always be a
**   '+' or '-' after the 'e' in scientific notation
*/
PR_PUBLIC_API(void)
PR_cnvtf(char *buf,int bufsz, int prcsn,double fval)
{
    intN decpt,sign,numdigits;
    char *num, *nump;
    char *bufp = buf;
    char *endnum;

	/* If anything fails, we store an empty string in 'buf' */
	num = (char *)MALLOC(bufsz);
	if (num == NULL) {
		buf[0] = '\0';
		return;
	}
	/* XXX Why use mode 1? */
	if (PR_dtoa(fval,1,prcsn,&decpt,&sign,&endnum,num,bufsz)
			== PR_FALSE) {
		buf[0] = '\0';
		goto done;
	}
	numdigits = endnum - num;
	nump = num;

	/* If negative and not signed zero and not a NaN, print leading "-". */
	if (sign &&
	    !(word0(fval) == Sign_bit && word1(fval) == 0) &&
	    !((word0(fval) & Exp_mask) == Exp_mask &&
	      (word1(fval) || (word0(fval) & 0xfffff)))) {
	    *bufp++ = '-';
	}

	if(decpt == 9999){
		while((*bufp++ = *nump++) != 0) ;
		goto done;
	}

	if(decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5){
	    *bufp++ = *nump++;
	    if(numdigits != 1){
			*bufp++ = '.';
	    }

	    while(*nump != '\0'){
			*bufp++ = *nump++;
	    }
	    *bufp++ = 'e';
	    PR_snprintf(bufp,bufsz - (bufp - buf), "%+d",decpt-1);
	}
	else if(decpt >= 0){
	    if (decpt == 0){
			*bufp++ = '0';
	    }
	    else {
		while(decpt--){
			if(*nump != '\0'){
				*bufp++ = *nump++;
			}
			else {
				*bufp++ = '0';
			}
		}
	    }
	    if(*nump != '\0'){
			*bufp++ = '.';
			while(*nump != '\0'){
				*bufp++ = *nump++;
			}
	    }
	    *bufp++ = '\0';
	}
	else if(decpt < 0){
	    *bufp++ = '0';
	    *bufp++ = '.';
	    while(decpt++){
			*bufp++ = '0';
	    }
	    
	    while(*nump != '\0'){
			*bufp++ = *nump++;
	    }
	    *bufp++ = '\0';
	}
done:
        free(num);



( run in 0.984 second using v1.01-cache-2.11-cpan-39bf76dae61 )