in mysql_strings/dtoa.cc [1273:1840]
static double my_strtod_int(const char *s00, const char **se, int *error,
char *buf, size_t buf_size) {
int scale;
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c = 0, dsign, e, e1, esign, i, j, k,
nd, nd0, nf, nz, nz0, sign;
const char *s, *s0, *s1, *end = *se;
double aadj, aadj1;
U aadj2, adj, rv, rv0;
Long L;
ULong y, z;
Bigint *bb = nullptr, *bb1, *bd = nullptr, *bd0, *bs = nullptr,
*delta = nullptr;
#ifdef Honor_FLT_ROUNDS
int rounding;
#endif
Stack_alloc alloc;
*error = 0;
alloc.begin = alloc.free = buf;
alloc.end = buf + buf_size;
memset(alloc.freelist, 0, sizeof(alloc.freelist));
sign = nz0 = nz = 0;
dval(&rv) = 0.;
for (s = s00; s < end; s++) switch (*s) {
case '-':
sign = 1;
[[fallthrough]];
case '+':
s++;
goto break2;
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
continue;
default:
goto break2;
}
break2:
if (s >= end) goto ret0;
// Gobble up leading zeros.
if (*s == '0') {
nz0 = 1;
while (++s < end && *s == '0')
;
if (s >= end) goto ret;
}
s0 = s;
y = z = 0;
for (nd = nf = 0; s < end && (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 (s < end && c == '.') {
if (++s < end) c = *s;
// Only leading zeros, now count number of leading zeros after the '.'
if (!nd) {
for (; s < end; ++s) {
c = *s;
if (c != '0') break;
nz++;
}
if (s < end && c > '0' && c <= '9') {
s0 = s;
nf += nz;
nz = 0;
} else
goto dig_done;
}
for (; s < end; ++s) {
c = *s;
if (c < '0' || c > '9') break;
// We have seen some digits, but not enough of them are non-zero.
// Gobble up all the rest of the digits, and look for exponent.
if (nd > 0 && nz > DBL_MAX_10_EXP) {
continue;
}
/*
Here we are parsing the fractional part.
We can stop counting digits after a while: the extra digits
will not contribute to the actual result produced by s2b().
We have to continue scanning, in case there is an exponent part.
*/
if (nd < 2 * DBL_DIG) {
nz++;
if (c -= '0') {
nf += nz;
for (i = 1; i < nz; i++)
if (nd++ < 9)
y *= 10;
else if (nd <= DBL_DIG + 1)
z *= 10;
if (nd++ < 9)
y = 10 * y + c;
else if (nd <= DBL_DIG + 1)
z = 10 * z + c;
nz = 0;
}
}
}
}
dig_done:
e = 0;
if (s < end && (c == 'e' || c == 'E')) {
if (!nd && !nz && !nz0) goto ret0;
s00 = s;
esign = 0;
if (++s < end) switch (c = *s) {
case '-':
esign = 1;
[[fallthrough]];
case '+':
if (++s < end) c = *s;
}
if (s < end && c >= '0' && c <= '9') {
while (s < end && c == '0') c = *++s;
if (s < end && c > '0' && c <= '9') {
L = c - '0';
s1 = s;
// Avoid overflow in loop body below.
while (++s < end && (c = *s) >= '0' && c <= '9' &&
L < (std::numeric_limits<Long>::max() - 255) / 10) {
L = 10 * L + c - '0';
}
if (s - s1 > 8 || L > 19999)
/* Avoid confusion from exponents
* so large that e might overflow.
*/
e = 19999; /* safe for 16 bit ints */
else
e = (int)L;
if (esign) e = -e;
} else
e = 0;
} else
s = s00;
}
if (!nd) {
if (!nz && !nz0) {
ret0:
s = s00;
sign = 0;
}
goto ret;
}
e1 = e -= nf;
/*
Now we have nd0 digits, starting at s0, followed by a
decimal point, followed by nd-nd0 digits. The number we're
after is the integer represented by those digits times
10**e
*/
if (!nd0) nd0 = nd;
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
dval(&rv) = y;
if (k > 9) {
dval(&rv) = tens[k - 9] * dval(&rv) + z;
}
bd0 = nullptr;
if (nd <= DBL_DIG
#ifndef Honor_FLT_ROUNDS
&& Flt_Rounds == 1
#endif
) {
if (!e) goto ret;
if (e > 0) {
if (e <= Ten_pmax) {
#ifdef Honor_FLT_ROUNDS
/* round correctly FLT_ROUNDS = 2 or 3 */
if (sign) {
rv.d = -rv.d;
sign = 0;
}
#endif
/* rv = */ rounded_product(dval(&rv), tens[e]);
goto ret;
}
i = DBL_DIG - nd;
if (e <= Ten_pmax + i) {
/*
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.d = -rv.d;
sign = 0;
}
#endif
e -= i;
dval(&rv) *= tens[i];
/* rv = */ rounded_product(dval(&rv), tens[e]);
goto ret;
}
}
#ifndef Inaccurate_Divide
else if (e >= -Ten_pmax) {
#ifdef Honor_FLT_ROUNDS
/* round correctly FLT_ROUNDS = 2 or 3 */
if (sign) {
rv.d = -rv.d;
sign = 0;
}
#endif
/* rv = */ rounded_quotient(dval(&rv), tens[-e]);
goto ret;
}
#endif
}
e1 += nd - k;
scale = 0;
#ifdef Honor_FLT_ROUNDS
if ((rounding = Flt_Rounds) >= 2) {
if (sign)
rounding = rounding == 2 ? 0 : 2;
else if (rounding != 2)
rounding = 0;
}
#endif
/* Get starting approximation = rv * 10**e1 */
if (e1 > 0) {
if ((i = e1 & 15)) dval(&rv) *= tens[i];
if (e1 &= ~15) {
if (e1 > DBL_MAX_10_EXP) {
ovfl:
*error = EOVERFLOW;
/* Can't trust HUGE_VAL */
#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;
#endif /*Honor_FLT_ROUNDS*/
if (bd0) goto retfree;
goto ret;
}
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) {
e1 = -e1;
if ((i = e1 & 15)) dval(&rv) /= tens[i];
if ((e1 >>= 4)) {
if (e1 >= 1 << n_bigtens) goto undfl;
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;
}
if (!dval(&rv)) {
undfl:
dval(&rv) = 0.;
if (bd0) goto retfree;
goto ret;
}
}
}
/* Now the hard part -- adjusting rv to the correct value.*/
/* Put digits into bd: true value = bd * 10^e */
bd0 = s2b(s0, nd0, nd, y, &alloc);
for (;;) {
bd = Balloc(bd0->k, &alloc);
Bcopy(bd, bd0);
bb = d2b(&rv, &bbe, &bbbits, &alloc); /* rv = bb * 2^bbe */
bs = i2b(1, &alloc);
if (e >= 0) {
bb2 = bb5 = 0;
bd2 = bd5 = e;
} 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
j = bbe - scale;
i = j + bbbits - 1; /* logb(rv) */
if (i < Emin) /* denormal */
j += P - Emin;
else
j = P + 1 - bbbits;
bb2 += j;
bd2 += j;
bd2 += scale;
i = bb2 < bd2 ? bb2 : bd2;
if (i > bs2) i = bs2;
if (i > 0) {
bb2 -= i;
bd2 -= i;
bs2 -= i;
}
if (bb5 > 0) {
bs = pow5mult(bs, bb5, &alloc);
bb1 = mult(bs, bb, &alloc);
Bfree(bb, &alloc);
bb = bb1;
}
if (bb2 > 0) bb = lshift(bb, bb2, &alloc);
if (bd5 > 0) bd = pow5mult(bd, bd5, &alloc);
if (bd2 > 0) bd = lshift(bd, bd2, &alloc);
if (bs2 > 0) bs = lshift(bs, bs2, &alloc);
delta = diff(bb, bd, &alloc);
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->p.x[0] && delta->wds <= 1) {
/* exact */
break;
}
if (rounding) {
if (dsign) {
adj.d = 1.;
goto apply_adj;
}
} else if (!dsign) {
adj.d = -1.;
if (!word1(&rv) && !(word0(&rv) & Frac_mask)) {
y = word0(&rv) & Exp_mask;
if (!scale || y > 2 * P * Exp_msk1) {
delta = lshift(delta, Log2P, &alloc);
if (cmp(delta, bs) <= 0) adj.d = -0.5;
}
}
apply_adj:
if (scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1)
word0(&adj) += (2 * P + 1) * Exp_msk1 - y;
dval(&rv) += adj.d * ulp(&rv);
}
break;
}
adj.d = ratio(delta, bs);
if (adj.d < 1.) adj.d = 1.;
if (adj.d <= 0x7ffffffe) {
/* adj = rounding ? ceil(adj) : floor(adj); */
y = adj.d;
if (y != adj.d) {
if (!((rounding >> 1) ^ dsign)) y++;
adj.d = y;
}
}
if (scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1)
word0(&adj) += (2 * P + 1) * Exp_msk1 - y;
adj.d *= ulp(&rv);
if (dsign)
dval(&rv) += adj.d;
else
dval(&rv) -= adj.d;
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 ||
(word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1) {
break;
}
if (!delta->p.x[0] && delta->wds <= 1) {
/* exact result */
break;
}
delta = lshift(delta, Log2P, &alloc);
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) ==
((scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1)
? (0xffffffff &
(0xffffffff << (2 * P + 1 - (y >> Exp_shift))))
: 0xffffffff)) {
/*boundary case -- increment exponent*/
word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1;
word1(&rv) = 0;
dsign = 0;
break;
}
} else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
drop_down:
/* boundary case -- decrement exponent */
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;
}
}
L = (word0(&rv) & Exp_mask) - Exp_msk1;
word0(&rv) = L | Bndry_mask1;
word1(&rv) = 0xffffffff;
break;
}
if (!(word1(&rv) & LSB)) break;
if (dsign)
dval(&rv) += ulp(&rv);
else {
dval(&rv) -= ulp(&rv);
if (!dval(&rv)) goto undfl;
}
dsign = 1 - dsign;
break;
}
if ((aadj = ratio(delta, bs)) <= 2.) {
if (dsign)
aadj = aadj1 = 1.;
else if (word1(&rv) || word0(&rv) & Bndry_mask) {
if (word1(&rv) == Tiny1 && !word0(&rv)) goto undfl;
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.d = aadj1 * ulp(&rv);
dval(&rv) += adj.d;
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 {
if (scale && y <= 2 * P * Exp_msk1) {
if (aadj <= 0x7fffffff) {
if ((z = (ULong)aadj) <= 0) z = 1;
aadj = z;
aadj1 = dsign ? aadj : -aadj;
}
dval(&aadj2) = aadj1;
word0(&aadj2) += (2 * P + 1) * Exp_msk1 - y;
aadj1 = dval(&aadj2);
adj.d = aadj1 * ulp(&rv);
dval(&rv) += adj.d;
if (rv.d == 0.) goto undfl;
} else {
adj.d = aadj1 * ulp(&rv);
dval(&rv) += adj.d;
}
}
z = word0(&rv) & Exp_mask;
if (!scale)
if (y == z) {
/* Can we stop now? */
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)
break;
}
cont:
Bfree(bb, &alloc);
Bfree(bd, &alloc);
Bfree(bs, &alloc);
Bfree(delta, &alloc);
}
if (scale) {
word0(&rv0) = Exp_1 - 2 * P * Exp_msk1;
word1(&rv0) = 0;
dval(&rv) *= dval(&rv0);
}
retfree:
Bfree(bb, &alloc);
Bfree(bd, &alloc);
Bfree(bs, &alloc);
Bfree(bd0, &alloc);
Bfree(delta, &alloc);
ret:
*se = s;
return sign ? -dval(&rv) : dval(&rv);
}