📄 dtoa.cpp
字号:
* special case of mantissa a power of two. */ if (dsign || word1(rv) || word0(rv) & Bndry_mask#ifdef Avoid_Underflow || (word0(rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1#else || (word0(rv) & Exp_mask) <= Exp_msk1#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) == (#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; word1(rv) = 0;#ifdef Avoid_Underflow dsign = 0;#endif break; } } else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {drop_down: /* boundary case -- decrement exponent */#ifdef Sudden_Underflow /*{{*/ L = word0(rv) & Exp_mask;#ifdef Avoid_Underflow if (L <= (scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1))#else if (L <= Exp_msk1)#endif /*Avoid_Underflow*/ goto undfl; L -= Exp_msk1;#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 /*Sudden_Underflow}}*/ word0(rv) = L | Bndry_mask1; word1(rv) = 0xffffffff; break; } if (!(word1(rv) & LSB)) break; if (dsign) dval(rv) += ulp(dval(rv)); else { dval(rv) -= ulp(dval(rv));#ifndef Sudden_Underflow if (!dval(rv)) goto undfl;#endif }#ifdef Avoid_Underflow dsign = 1 - dsign;#endif break; } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) aadj = aadj1 = 1.; else if (word1(rv) || word0(rv) & Bndry_mask) {#ifndef Sudden_Underflow if (word1(rv) == Tiny1 && !word0(rv)) goto undfl;#endif aadj = 1.; aadj1 = -1.; } else { /* special case -- power of FLT_RADIX to be */ /* rounded down... */ if (aadj < 2. / FLT_RADIX) aadj = 1. / FLT_RADIX; else aadj *= 0.5; aadj1 = -aadj; } } else { aadj *= 0.5; aadj1 = dsign ? aadj : -aadj;#ifdef Check_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) aadj1 += 0.5;#endif /*Check_FLT_ROUNDS*/ } y = word0(rv) & Exp_mask; /* Check for overflow */ if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) { dval(rv0) = dval(rv); word0(rv) -= P * Exp_msk1; 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) goto ovfl; word0(rv) = Big0; word1(rv) = Big1; goto cont; } else word0(rv) += P * Exp_msk1; } else {#ifdef Avoid_Underflow if (scale && y <= 2 * P * Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = (uint32_t)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) { dval(rv0) = dval(rv); word0(rv) += P * Exp_msk1; adj = aadj1 * ulp(dval(rv)); dval(rv) += adj; if ((word0(rv) & Exp_mask) <= P * Exp_msk1) { if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) goto undfl; word0(rv) = Tiny0; word1(rv) = Tiny1; goto cont; } else word0(rv) -= P * Exp_msk1; } 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., * y <= (P - 1) * Exp_msk1), we must adjust aadj to avoid * trouble from bits lost to denormalization; * example: 1.2e-307 . */ 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*/ } z = word0(rv) & Exp_mask;#ifndef SET_INEXACT#ifdef Avoid_Underflow if (!scale)#endif if (y == z) { /* Can we stop now? */ L = (int32_t)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) break; }#endifcont: 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); }#endifretfree: Bfree(bb); Bfree(bd); Bfree(bs); Bfree(bd0); Bfree(delta);ret: if (se) *se = const_cast<char*>(s); return sign ? -dval(rv) : dval(rv);}static int quorem(Bigint* b, Bigint* S){ int n; uint32_t *bx, *bxe, q, *sx, *sxe;#ifdef USE_LONG_LONG unsigned long long borrow, carry, y, ys;#else uint32_t borrow, carry, y, ys;#ifdef Pack_32 uint32_t si, z, zs;#endif#endif n = S->wds; ASSERT_WITH_MESSAGE(b->wds <= n, "oversize b in quorem"); 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 */ ASSERT_WITH_MESSAGE(q <= 9, "oversized quotient in quorem"); if (q) { borrow = 0; carry = 0; do {#ifdef USE_LONG_LONG ys = *sx++ * (unsigned long long)q + carry; carry = ys >> 32; y = *bx - (ys & 0xffffffffUL) - borrow; borrow = y >> 32 & (uint32_t)1; *bx++ = (uint32_t)y & 0xffffffffUL;#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 & 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 & 0x10000) >> 16; *bx++ = y & 0xffff;#endif#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 USE_LONG_LONG ys = *sx++ + carry; carry = ys >> 32; y = *bx - (ys & 0xffffffffUL) - borrow; borrow = y >> 32 & (uint32_t)1; *bx++ = (uint32_t)y & 0xffffffffUL;#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 & 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 & 0x10000) >> 16; *bx++ = y & 0xffff;#endif#endif } while (sx <= sxe); bx = b->x; bxe = bx + n; if (!*bxe) { while (--bxe > bx && !*bxe) --n; b->wds = n; } } return q;}#if !ENABLE(JSC_MULTIPLE_THREADS)static char* dtoa_result;#endifstatic char* rv_alloc(int i){ int k; int j = sizeof(uint32_t); for (k = 0; sizeof(Bigint) - sizeof(uint32_t) - sizeof(int) + j <= (unsigned)i; j <<= 1) k++; int* r = (int*)Balloc(k); *r = k; return#if !ENABLE(JSC_MULTIPLE_THREADS) dtoa_result =#endif (char*)(r + 1);}static char* nrv_alloc(const char* s, char** rve, int n){ char* rv = rv_alloc(n); char* t = rv; 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. */void freedtoa(char* s){ Bigint* b = (Bigint*)((int*)s - 1); b->maxwds = 1 << (b->k = *(int*)b); Bfree(b);#if !ENABLE(JSC_MULTIPLE_THREADS) if (s == dtoa_result) dtoa_result = 0;#endif}/* 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 int32_t * calculation. */char* dtoa(double d, 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. */ int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0, j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, spec_case, try_quick; int32_t L;#ifndef Sudden_Underflow int denorm; uint32_t x;#endif Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S; double d2, ds, eps; char *s, *s0;#ifdef SET_INEXACT int inexact, oldinexact;#endif#if !ENABLE(JSC_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -