13e12c5d1SDavid du Colombier #include "fconv.h"
23e12c5d1SDavid du Colombier
33e12c5d1SDavid du Colombier static int quorem(Bigint *, Bigint *);
43e12c5d1SDavid du Colombier
53e12c5d1SDavid du Colombier /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
63e12c5d1SDavid du Colombier *
73e12c5d1SDavid du Colombier * Inspired by "How to Print Floating-Point Numbers Accurately" by
83e12c5d1SDavid du Colombier * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
93e12c5d1SDavid du Colombier *
103e12c5d1SDavid du Colombier * Modifications:
113e12c5d1SDavid du Colombier * 1. Rather than iterating, we use a simple numeric overestimate
123e12c5d1SDavid du Colombier * to determine k = floor(log10(d)). We scale relevant
133e12c5d1SDavid du Colombier * quantities using O(log2(k)) rather than O(k) multiplications.
143e12c5d1SDavid du Colombier * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
153e12c5d1SDavid du Colombier * try to generate digits strictly left to right. Instead, we
163e12c5d1SDavid du Colombier * compute with fewer bits and propagate the carry if necessary
173e12c5d1SDavid du Colombier * when rounding the final digit up. This is often faster.
183e12c5d1SDavid du Colombier * 3. Under the assumption that input will be rounded nearest,
193e12c5d1SDavid du Colombier * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
203e12c5d1SDavid du Colombier * That is, we allow equality in stopping tests when the
213e12c5d1SDavid du Colombier * round-nearest rule will give the same floating-point value
223e12c5d1SDavid du Colombier * as would satisfaction of the stopping test with strict
233e12c5d1SDavid du Colombier * inequality.
243e12c5d1SDavid du Colombier * 4. We remove common factors of powers of 2 from relevant
253e12c5d1SDavid du Colombier * quantities.
263e12c5d1SDavid du Colombier * 5. When converting floating-point integers less than 1e16,
273e12c5d1SDavid du Colombier * we use floating-point arithmetic rather than resorting
283e12c5d1SDavid du Colombier * to multiple-precision integers.
293e12c5d1SDavid du Colombier * 6. When asked to produce fewer than 15 digits, we first try
303e12c5d1SDavid du Colombier * to get by with floating-point arithmetic; we resort to
313e12c5d1SDavid du Colombier * multiple-precision integer arithmetic only if we cannot
323e12c5d1SDavid du Colombier * guarantee that the floating-point calculation has given
333e12c5d1SDavid du Colombier * the correctly rounded result. For k requested digits and
343e12c5d1SDavid du Colombier * "uniformly" distributed input, the probability is
353e12c5d1SDavid du Colombier * something like 10^(k-15) that we must resort to the long
363e12c5d1SDavid du Colombier * calculation.
373e12c5d1SDavid du Colombier */
383e12c5d1SDavid du Colombier
393e12c5d1SDavid du Colombier char *
_dtoa(double darg,int mode,int ndigits,int * decpt,int * sign,char ** rve)403e12c5d1SDavid du Colombier _dtoa(double darg, int mode, int ndigits, int *decpt, int *sign, char **rve)
413e12c5d1SDavid du Colombier {
423e12c5d1SDavid du Colombier /* Arguments ndigits, decpt, sign are similar to those
433e12c5d1SDavid du Colombier of ecvt and fcvt; trailing zeros are suppressed from
443e12c5d1SDavid du Colombier the returned string. If not null, *rve is set to point
453e12c5d1SDavid du Colombier to the end of the return value. If d is +-Infinity or NaN,
463e12c5d1SDavid du Colombier then *decpt is set to 9999.
473e12c5d1SDavid du Colombier
483e12c5d1SDavid du Colombier mode:
493e12c5d1SDavid du Colombier 0 ==> shortest string that yields d when read in
503e12c5d1SDavid du Colombier and rounded to nearest.
513e12c5d1SDavid du Colombier 1 ==> like 0, but with Steele & White stopping rule;
523e12c5d1SDavid du Colombier e.g. with IEEE P754 arithmetic , mode 0 gives
533e12c5d1SDavid du Colombier 1e23 whereas mode 1 gives 9.999999999999999e22.
543e12c5d1SDavid du Colombier 2 ==> max(1,ndigits) significant digits. This gives a
553e12c5d1SDavid du Colombier return value similar to that of ecvt, except
563e12c5d1SDavid du Colombier that trailing zeros are suppressed.
573e12c5d1SDavid du Colombier 3 ==> through ndigits past the decimal point. This
583e12c5d1SDavid du Colombier gives a return value similar to that from fcvt,
593e12c5d1SDavid du Colombier except that trailing zeros are suppressed, and
603e12c5d1SDavid du Colombier ndigits can be negative.
613e12c5d1SDavid du Colombier 4-9 should give the same return values as 2-3, i.e.,
623e12c5d1SDavid du Colombier 4 <= mode <= 9 ==> same return as mode
633e12c5d1SDavid du Colombier 2 + (mode & 1). These modes are mainly for
643e12c5d1SDavid du Colombier debugging; often they run slower but sometimes
653e12c5d1SDavid du Colombier faster than modes 2-3.
663e12c5d1SDavid du Colombier 4,5,8,9 ==> left-to-right digit generation.
673e12c5d1SDavid du Colombier 6-9 ==> don't try fast floating-point estimate
683e12c5d1SDavid du Colombier (if applicable).
693e12c5d1SDavid du Colombier
703e12c5d1SDavid du Colombier Values of mode other than 0-9 are treated as mode 0.
713e12c5d1SDavid du Colombier
723e12c5d1SDavid du Colombier Sufficient space is allocated to the return value
733e12c5d1SDavid du Colombier to hold the suppressed trailing zeros.
743e12c5d1SDavid du Colombier */
753e12c5d1SDavid du Colombier
763e12c5d1SDavid du Colombier int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
773e12c5d1SDavid du Colombier j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
783e12c5d1SDavid du Colombier spec_case, try_quick;
793e12c5d1SDavid du Colombier long L;
803e12c5d1SDavid du Colombier #ifndef Sudden_Underflow
813e12c5d1SDavid du Colombier int denorm;
823e12c5d1SDavid du Colombier unsigned long x;
833e12c5d1SDavid du Colombier #endif
843e12c5d1SDavid du Colombier Bigint *b, *b1, *delta, *mlo, *mhi, *S;
853e12c5d1SDavid du Colombier double ds;
863e12c5d1SDavid du Colombier Dul d2, eps;
873e12c5d1SDavid du Colombier char *s, *s0;
883e12c5d1SDavid du Colombier static Bigint *result;
893e12c5d1SDavid du Colombier static int result_k;
903e12c5d1SDavid du Colombier Dul d;
913e12c5d1SDavid du Colombier
92*22df390cSDavid du Colombier mlo = 0;
933e12c5d1SDavid du Colombier d.d = darg;
943e12c5d1SDavid du Colombier if (result) {
953e12c5d1SDavid du Colombier result->k = result_k;
963e12c5d1SDavid du Colombier result->maxwds = 1 << result_k;
973e12c5d1SDavid du Colombier Bfree(result);
983e12c5d1SDavid du Colombier result = 0;
993e12c5d1SDavid du Colombier }
1003e12c5d1SDavid du Colombier
1013e12c5d1SDavid du Colombier if (word0(d) & Sign_bit) {
1023e12c5d1SDavid du Colombier /* set sign for everything, including 0's and NaNs */
1033e12c5d1SDavid du Colombier *sign = 1;
1043e12c5d1SDavid du Colombier word0(d) &= ~Sign_bit; /* clear sign bit */
1053e12c5d1SDavid du Colombier }
1063e12c5d1SDavid du Colombier else
1073e12c5d1SDavid du Colombier *sign = 0;
1083e12c5d1SDavid du Colombier
1093e12c5d1SDavid du Colombier #if defined(IEEE_Arith) + defined(VAX)
1103e12c5d1SDavid du Colombier #ifdef IEEE_Arith
1113e12c5d1SDavid du Colombier if ((word0(d) & Exp_mask) == Exp_mask)
1123e12c5d1SDavid du Colombier #else
1133e12c5d1SDavid du Colombier if (word0(d) == 0x8000)
1143e12c5d1SDavid du Colombier #endif
1153e12c5d1SDavid du Colombier {
1163e12c5d1SDavid du Colombier /* Infinity or NaN */
1173e12c5d1SDavid du Colombier *decpt = 9999;
1183e12c5d1SDavid du Colombier s =
1193e12c5d1SDavid du Colombier #ifdef IEEE_Arith
1203e12c5d1SDavid du Colombier !word1(d) && !(word0(d) & 0xfffff) ? "Infinity" :
1213e12c5d1SDavid du Colombier #endif
1223e12c5d1SDavid du Colombier "NaN";
1233e12c5d1SDavid du Colombier if (rve)
1243e12c5d1SDavid du Colombier *rve =
1253e12c5d1SDavid du Colombier #ifdef IEEE_Arith
1263e12c5d1SDavid du Colombier s[3] ? s + 8 :
1273e12c5d1SDavid du Colombier #endif
1283e12c5d1SDavid du Colombier s + 3;
1293e12c5d1SDavid du Colombier return s;
1303e12c5d1SDavid du Colombier }
1313e12c5d1SDavid du Colombier #endif
1323e12c5d1SDavid du Colombier #ifdef IBM
1333e12c5d1SDavid du Colombier d.d += 0; /* normalize */
1343e12c5d1SDavid du Colombier #endif
1353e12c5d1SDavid du Colombier if (!d.d) {
1363e12c5d1SDavid du Colombier *decpt = 1;
1373e12c5d1SDavid du Colombier s = "0";
1383e12c5d1SDavid du Colombier if (rve)
1393e12c5d1SDavid du Colombier *rve = s + 1;
1403e12c5d1SDavid du Colombier return s;
1413e12c5d1SDavid du Colombier }
1423e12c5d1SDavid du Colombier
1433e12c5d1SDavid du Colombier b = d2b(d.d, &be, &bbits);
1443e12c5d1SDavid du Colombier #ifdef Sudden_Underflow
1453e12c5d1SDavid du Colombier i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
1463e12c5d1SDavid du Colombier #else
1473e12c5d1SDavid du Colombier if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) {
1483e12c5d1SDavid du Colombier #endif
1493e12c5d1SDavid du Colombier d2.d = d.d;
1503e12c5d1SDavid du Colombier word0(d2) &= Frac_mask1;
1513e12c5d1SDavid du Colombier word0(d2) |= Exp_11;
1523e12c5d1SDavid du Colombier #ifdef IBM
1533e12c5d1SDavid du Colombier if (j = 11 - hi0bits(word0(d2) & Frac_mask))
1543e12c5d1SDavid du Colombier d2.d /= 1 << j;
1553e12c5d1SDavid du Colombier #endif
1563e12c5d1SDavid du Colombier
1573e12c5d1SDavid du Colombier /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
1583e12c5d1SDavid du Colombier * log10(x) = log(x) / log(10)
1593e12c5d1SDavid du Colombier * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
1603e12c5d1SDavid du Colombier * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
1613e12c5d1SDavid du Colombier *
1623e12c5d1SDavid du Colombier * This suggests computing an approximation k to log10(d) by
1633e12c5d1SDavid du Colombier *
1643e12c5d1SDavid du Colombier * k = (i - Bias)*0.301029995663981
1653e12c5d1SDavid du Colombier * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
1663e12c5d1SDavid du Colombier *
1673e12c5d1SDavid du Colombier * We want k to be too large rather than too small.
1683e12c5d1SDavid du Colombier * The error in the first-order Taylor series approximation
1693e12c5d1SDavid du Colombier * is in our favor, so we just round up the constant enough
1703e12c5d1SDavid du Colombier * to compensate for any error in the multiplication of
1713e12c5d1SDavid du Colombier * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
1723e12c5d1SDavid du Colombier * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
1733e12c5d1SDavid du Colombier * adding 1e-13 to the constant term more than suffices.
1743e12c5d1SDavid du Colombier * Hence we adjust the constant term to 0.1760912590558.
1753e12c5d1SDavid du Colombier * (We could get a more accurate k by invoking log10,
1763e12c5d1SDavid du Colombier * but this is probably not worthwhile.)
1773e12c5d1SDavid du Colombier */
1783e12c5d1SDavid du Colombier
1793e12c5d1SDavid du Colombier i -= Bias;
1803e12c5d1SDavid du Colombier #ifdef IBM
1813e12c5d1SDavid du Colombier i <<= 2;
1823e12c5d1SDavid du Colombier i += j;
1833e12c5d1SDavid du Colombier #endif
1843e12c5d1SDavid du Colombier #ifndef Sudden_Underflow
1853e12c5d1SDavid du Colombier denorm = 0;
1863e12c5d1SDavid du Colombier }
1873e12c5d1SDavid du Colombier else {
1883e12c5d1SDavid du Colombier /* d is denormalized */
1893e12c5d1SDavid du Colombier
1903e12c5d1SDavid du Colombier i = bbits + be + (Bias + (P-1) - 1);
1913e12c5d1SDavid du Colombier x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32
1923e12c5d1SDavid du Colombier : word1(d) << 32 - i;
1933e12c5d1SDavid du Colombier d2.d = x;
1943e12c5d1SDavid du Colombier word0(d2) -= 31*Exp_msk1; /* adjust exponent */
1953e12c5d1SDavid du Colombier i -= (Bias + (P-1) - 1) + 1;
1963e12c5d1SDavid du Colombier denorm = 1;
1973e12c5d1SDavid du Colombier }
1983e12c5d1SDavid du Colombier #endif
1993e12c5d1SDavid du Colombier ds = (d2.d-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
2003e12c5d1SDavid du Colombier k = floor(ds);
2013e12c5d1SDavid du Colombier k_check = 1;
2023e12c5d1SDavid du Colombier if (k >= 0 && k <= Ten_pmax) {
2033e12c5d1SDavid du Colombier if (d.d < tens[k])
2043e12c5d1SDavid du Colombier k--;
2053e12c5d1SDavid du Colombier k_check = 0;
2063e12c5d1SDavid du Colombier }
2073e12c5d1SDavid du Colombier j = bbits - i - 1;
2083e12c5d1SDavid du Colombier if (j >= 0) {
2093e12c5d1SDavid du Colombier b2 = 0;
2103e12c5d1SDavid du Colombier s2 = j;
2113e12c5d1SDavid du Colombier }
2123e12c5d1SDavid du Colombier else {
2133e12c5d1SDavid du Colombier b2 = -j;
2143e12c5d1SDavid du Colombier s2 = 0;
2153e12c5d1SDavid du Colombier }
2163e12c5d1SDavid du Colombier if (k >= 0) {
2173e12c5d1SDavid du Colombier b5 = 0;
2183e12c5d1SDavid du Colombier s5 = k;
2193e12c5d1SDavid du Colombier s2 += k;
2203e12c5d1SDavid du Colombier }
2213e12c5d1SDavid du Colombier else {
2223e12c5d1SDavid du Colombier b2 -= k;
2233e12c5d1SDavid du Colombier b5 = -k;
2243e12c5d1SDavid du Colombier s5 = 0;
2253e12c5d1SDavid du Colombier }
2263e12c5d1SDavid du Colombier if (mode < 0 || mode > 9)
2273e12c5d1SDavid du Colombier mode = 0;
2283e12c5d1SDavid du Colombier try_quick = 1;
2293e12c5d1SDavid du Colombier if (mode > 5) {
2303e12c5d1SDavid du Colombier mode -= 4;
2313e12c5d1SDavid du Colombier try_quick = 0;
2323e12c5d1SDavid du Colombier }
2333e12c5d1SDavid du Colombier leftright = 1;
234*22df390cSDavid du Colombier ilim = ilim1 = -1;
2353e12c5d1SDavid du Colombier switch(mode) {
2363e12c5d1SDavid du Colombier case 0:
2373e12c5d1SDavid du Colombier case 1:
2383e12c5d1SDavid du Colombier ilim = ilim1 = -1;
2393e12c5d1SDavid du Colombier i = 18;
2403e12c5d1SDavid du Colombier ndigits = 0;
2413e12c5d1SDavid du Colombier break;
2423e12c5d1SDavid du Colombier case 2:
2433e12c5d1SDavid du Colombier leftright = 0;
2443e12c5d1SDavid du Colombier /* no break */
2453e12c5d1SDavid du Colombier case 4:
2463e12c5d1SDavid du Colombier if (ndigits <= 0)
2473e12c5d1SDavid du Colombier ndigits = 1;
2483e12c5d1SDavid du Colombier ilim = ilim1 = i = ndigits;
2493e12c5d1SDavid du Colombier break;
2503e12c5d1SDavid du Colombier case 3:
2513e12c5d1SDavid du Colombier leftright = 0;
2523e12c5d1SDavid du Colombier /* no break */
2533e12c5d1SDavid du Colombier case 5:
2543e12c5d1SDavid du Colombier i = ndigits + k + 1;
2553e12c5d1SDavid du Colombier ilim = i;
2563e12c5d1SDavid du Colombier ilim1 = i - 1;
2573e12c5d1SDavid du Colombier if (i <= 0)
2583e12c5d1SDavid du Colombier i = 1;
2593e12c5d1SDavid du Colombier }
2603e12c5d1SDavid du Colombier j = sizeof(unsigned long);
261219b2ee8SDavid du Colombier for(result_k = 0; sizeof(Bigint) - sizeof(unsigned long) + j <= i;
2623e12c5d1SDavid du Colombier j <<= 1) result_k++;
2633e12c5d1SDavid du Colombier result = Balloc(result_k);
2643e12c5d1SDavid du Colombier s = s0 = (char *)result;
2653e12c5d1SDavid du Colombier
2663e12c5d1SDavid du Colombier if (ilim >= 0 && ilim <= Quick_max && try_quick) {
2673e12c5d1SDavid du Colombier
2683e12c5d1SDavid du Colombier /* Try to get by with floating-point arithmetic. */
2693e12c5d1SDavid du Colombier
2703e12c5d1SDavid du Colombier i = 0;
2713e12c5d1SDavid du Colombier d2.d = d.d;
2723e12c5d1SDavid du Colombier k0 = k;
2733e12c5d1SDavid du Colombier ilim0 = ilim;
2743e12c5d1SDavid du Colombier ieps = 2; /* conservative */
2753e12c5d1SDavid du Colombier if (k > 0) {
2763e12c5d1SDavid du Colombier ds = tens[k&0xf];
2773e12c5d1SDavid du Colombier j = k >> 4;
2783e12c5d1SDavid du Colombier if (j & Bletch) {
2793e12c5d1SDavid du Colombier /* prevent overflows */
2803e12c5d1SDavid du Colombier j &= Bletch - 1;
2813e12c5d1SDavid du Colombier d.d /= bigtens[n_bigtens-1];
2823e12c5d1SDavid du Colombier ieps++;
2833e12c5d1SDavid du Colombier }
2843e12c5d1SDavid du Colombier for(; j; j >>= 1, i++)
2853e12c5d1SDavid du Colombier if (j & 1) {
2863e12c5d1SDavid du Colombier ieps++;
2873e12c5d1SDavid du Colombier ds *= bigtens[i];
2883e12c5d1SDavid du Colombier }
2893e12c5d1SDavid du Colombier d.d /= ds;
2903e12c5d1SDavid du Colombier }
2913e12c5d1SDavid du Colombier else if (j1 = -k) {
2923e12c5d1SDavid du Colombier d.d *= tens[j1 & 0xf];
2933e12c5d1SDavid du Colombier for(j = j1 >> 4; j; j >>= 1, i++)
2943e12c5d1SDavid du Colombier if (j & 1) {
2953e12c5d1SDavid du Colombier ieps++;
2963e12c5d1SDavid du Colombier d.d *= bigtens[i];
2973e12c5d1SDavid du Colombier }
2983e12c5d1SDavid du Colombier }
2993e12c5d1SDavid du Colombier if (k_check && d.d < 1. && ilim > 0) {
3003e12c5d1SDavid du Colombier if (ilim1 <= 0)
3013e12c5d1SDavid du Colombier goto fast_failed;
3023e12c5d1SDavid du Colombier ilim = ilim1;
3033e12c5d1SDavid du Colombier k--;
3043e12c5d1SDavid du Colombier d.d *= 10.;
3053e12c5d1SDavid du Colombier ieps++;
3063e12c5d1SDavid du Colombier }
3073e12c5d1SDavid du Colombier eps.d = ieps*d.d + 7.;
3083e12c5d1SDavid du Colombier word0(eps) -= (P-1)*Exp_msk1;
3093e12c5d1SDavid du Colombier if (ilim == 0) {
3103e12c5d1SDavid du Colombier S = mhi = 0;
3113e12c5d1SDavid du Colombier d.d -= 5.;
3123e12c5d1SDavid du Colombier if (d.d > eps.d)
3133e12c5d1SDavid du Colombier goto one_digit;
3143e12c5d1SDavid du Colombier if (d.d < -eps.d)
3153e12c5d1SDavid du Colombier goto no_digits;
3163e12c5d1SDavid du Colombier goto fast_failed;
3173e12c5d1SDavid du Colombier }
3183e12c5d1SDavid du Colombier #ifndef No_leftright
3193e12c5d1SDavid du Colombier if (leftright) {
3203e12c5d1SDavid du Colombier /* Use Steele & White method of only
3213e12c5d1SDavid du Colombier * generating digits needed.
3223e12c5d1SDavid du Colombier */
3233e12c5d1SDavid du Colombier eps.d = 0.5/tens[ilim-1] - eps.d;
3243e12c5d1SDavid du Colombier for(i = 0;;) {
3253e12c5d1SDavid du Colombier L = floor(d.d);
3263e12c5d1SDavid du Colombier d.d -= L;
3273e12c5d1SDavid du Colombier *s++ = '0' + (int)L;
3283e12c5d1SDavid du Colombier if (d.d < eps.d)
3293e12c5d1SDavid du Colombier goto ret1;
3303e12c5d1SDavid du Colombier if (1. - d.d < eps.d)
3313e12c5d1SDavid du Colombier goto bump_up;
3323e12c5d1SDavid du Colombier if (++i >= ilim)
3333e12c5d1SDavid du Colombier break;
3343e12c5d1SDavid du Colombier eps.d *= 10.;
3353e12c5d1SDavid du Colombier d.d *= 10.;
3363e12c5d1SDavid du Colombier }
3373e12c5d1SDavid du Colombier }
3383e12c5d1SDavid du Colombier else {
3393e12c5d1SDavid du Colombier #endif
3403e12c5d1SDavid du Colombier /* Generate ilim digits, then fix them up. */
3413e12c5d1SDavid du Colombier eps.d *= tens[ilim-1];
3423e12c5d1SDavid du Colombier for(i = 1;; i++, d.d *= 10.) {
3433e12c5d1SDavid du Colombier L = floor(d.d);
3443e12c5d1SDavid du Colombier d.d -= L;
3453e12c5d1SDavid du Colombier *s++ = '0' + (int)L;
3463e12c5d1SDavid du Colombier if (i == ilim) {
3473e12c5d1SDavid du Colombier if (d.d > 0.5 + eps.d)
3483e12c5d1SDavid du Colombier goto bump_up;
3493e12c5d1SDavid du Colombier else if (d.d < 0.5 - eps.d) {
3503e12c5d1SDavid du Colombier while(*--s == '0');
3513e12c5d1SDavid du Colombier s++;
3523e12c5d1SDavid du Colombier goto ret1;
3533e12c5d1SDavid du Colombier }
3543e12c5d1SDavid du Colombier break;
3553e12c5d1SDavid du Colombier }
3563e12c5d1SDavid du Colombier }
3573e12c5d1SDavid du Colombier #ifndef No_leftright
3583e12c5d1SDavid du Colombier }
3593e12c5d1SDavid du Colombier #endif
3603e12c5d1SDavid du Colombier fast_failed:
3613e12c5d1SDavid du Colombier s = s0;
3623e12c5d1SDavid du Colombier d.d = d2.d;
3633e12c5d1SDavid du Colombier k = k0;
3643e12c5d1SDavid du Colombier ilim = ilim0;
3653e12c5d1SDavid du Colombier }
3663e12c5d1SDavid du Colombier
3673e12c5d1SDavid du Colombier /* Do we have a "small" integer? */
3683e12c5d1SDavid du Colombier
3693e12c5d1SDavid du Colombier if (be >= 0 && k <= Int_max) {
3703e12c5d1SDavid du Colombier /* Yes. */
3713e12c5d1SDavid du Colombier ds = tens[k];
3723e12c5d1SDavid du Colombier if (ndigits < 0 && ilim <= 0) {
3733e12c5d1SDavid du Colombier S = mhi = 0;
3743e12c5d1SDavid du Colombier if (ilim < 0 || d.d <= 5*ds)
3753e12c5d1SDavid du Colombier goto no_digits;
3763e12c5d1SDavid du Colombier goto one_digit;
3773e12c5d1SDavid du Colombier }
3783e12c5d1SDavid du Colombier for(i = 1;; i++) {
3793e12c5d1SDavid du Colombier L = floor(d.d / ds);
3803e12c5d1SDavid du Colombier d.d -= L*ds;
3813e12c5d1SDavid du Colombier #ifdef Check_FLT_ROUNDS
3823e12c5d1SDavid du Colombier /* If FLT_ROUNDS == 2, L will usually be high by 1 */
3833e12c5d1SDavid du Colombier if (d.d < 0) {
3843e12c5d1SDavid du Colombier L--;
3853e12c5d1SDavid du Colombier d.d += ds;
3863e12c5d1SDavid du Colombier }
3873e12c5d1SDavid du Colombier #endif
3883e12c5d1SDavid du Colombier *s++ = '0' + (int)L;
3893e12c5d1SDavid du Colombier if (i == ilim) {
3903e12c5d1SDavid du Colombier d.d += d.d;
3913e12c5d1SDavid du Colombier if (d.d > ds || d.d == ds && L & 1) {
3923e12c5d1SDavid du Colombier bump_up:
3933e12c5d1SDavid du Colombier while(*--s == '9')
3943e12c5d1SDavid du Colombier if (s == s0) {
3953e12c5d1SDavid du Colombier k++;
3963e12c5d1SDavid du Colombier *s = '0';
3973e12c5d1SDavid du Colombier break;
3983e12c5d1SDavid du Colombier }
3993e12c5d1SDavid du Colombier ++*s++;
4003e12c5d1SDavid du Colombier }
4013e12c5d1SDavid du Colombier break;
4023e12c5d1SDavid du Colombier }
4033e12c5d1SDavid du Colombier d.d *= 10.;
4043e12c5d1SDavid du Colombier if (d.d == 0.)
4053e12c5d1SDavid du Colombier break;
4063e12c5d1SDavid du Colombier }
4073e12c5d1SDavid du Colombier goto ret1;
4083e12c5d1SDavid du Colombier }
4093e12c5d1SDavid du Colombier
4103e12c5d1SDavid du Colombier m2 = b2;
4113e12c5d1SDavid du Colombier m5 = b5;
4123e12c5d1SDavid du Colombier mhi = mlo = 0;
4133e12c5d1SDavid du Colombier if (leftright) {
4143e12c5d1SDavid du Colombier if (mode < 2) {
4153e12c5d1SDavid du Colombier i =
4163e12c5d1SDavid du Colombier #ifndef Sudden_Underflow
4173e12c5d1SDavid du Colombier denorm ? be + (Bias + (P-1) - 1 + 1) :
4183e12c5d1SDavid du Colombier #endif
4193e12c5d1SDavid du Colombier #ifdef IBM
4203e12c5d1SDavid du Colombier 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
4213e12c5d1SDavid du Colombier #else
4223e12c5d1SDavid du Colombier 1 + P - bbits;
4233e12c5d1SDavid du Colombier #endif
4243e12c5d1SDavid du Colombier }
4253e12c5d1SDavid du Colombier else {
4263e12c5d1SDavid du Colombier j = ilim - 1;
4273e12c5d1SDavid du Colombier if (m5 >= j)
4283e12c5d1SDavid du Colombier m5 -= j;
4293e12c5d1SDavid du Colombier else {
4303e12c5d1SDavid du Colombier s5 += j -= m5;
4313e12c5d1SDavid du Colombier b5 += j;
4323e12c5d1SDavid du Colombier m5 = 0;
4333e12c5d1SDavid du Colombier }
4343e12c5d1SDavid du Colombier if ((i = ilim) < 0) {
4353e12c5d1SDavid du Colombier m2 -= i;
4363e12c5d1SDavid du Colombier i = 0;
4373e12c5d1SDavid du Colombier }
4383e12c5d1SDavid du Colombier }
4393e12c5d1SDavid du Colombier b2 += i;
4403e12c5d1SDavid du Colombier s2 += i;
4413e12c5d1SDavid du Colombier mhi = i2b(1);
4423e12c5d1SDavid du Colombier }
4433e12c5d1SDavid du Colombier if (m2 > 0 && s2 > 0) {
4443e12c5d1SDavid du Colombier i = m2 < s2 ? m2 : s2;
4453e12c5d1SDavid du Colombier b2 -= i;
4463e12c5d1SDavid du Colombier m2 -= i;
4473e12c5d1SDavid du Colombier s2 -= i;
4483e12c5d1SDavid du Colombier }
4493e12c5d1SDavid du Colombier if (b5 > 0) {
4503e12c5d1SDavid du Colombier if (leftright) {
4513e12c5d1SDavid du Colombier if (m5 > 0) {
4523e12c5d1SDavid du Colombier mhi = pow5mult(mhi, m5);
4533e12c5d1SDavid du Colombier b1 = mult(mhi, b);
4543e12c5d1SDavid du Colombier Bfree(b);
4553e12c5d1SDavid du Colombier b = b1;
4563e12c5d1SDavid du Colombier }
4573e12c5d1SDavid du Colombier if (j = b5 - m5)
4583e12c5d1SDavid du Colombier b = pow5mult(b, j);
4593e12c5d1SDavid du Colombier }
4603e12c5d1SDavid du Colombier else
4613e12c5d1SDavid du Colombier b = pow5mult(b, b5);
4623e12c5d1SDavid du Colombier }
4633e12c5d1SDavid du Colombier S = i2b(1);
4643e12c5d1SDavid du Colombier if (s5 > 0)
4653e12c5d1SDavid du Colombier S = pow5mult(S, s5);
4663e12c5d1SDavid du Colombier
4673e12c5d1SDavid du Colombier /* Check for special case that d is a normalized power of 2. */
468*22df390cSDavid du Colombier spec_case = 0;
4693e12c5d1SDavid du Colombier if (mode < 2) {
4703e12c5d1SDavid du Colombier if (!word1(d) && !(word0(d) & Bndry_mask)
4713e12c5d1SDavid du Colombier #ifndef Sudden_Underflow
4723e12c5d1SDavid du Colombier && word0(d) & Exp_mask
4733e12c5d1SDavid du Colombier #endif
4743e12c5d1SDavid du Colombier ) {
4753e12c5d1SDavid du Colombier /* The special case */
4763e12c5d1SDavid du Colombier b2 += Log2P;
4773e12c5d1SDavid du Colombier s2 += Log2P;
4783e12c5d1SDavid du Colombier spec_case = 1;
4793e12c5d1SDavid du Colombier }
4803e12c5d1SDavid du Colombier else
4813e12c5d1SDavid du Colombier spec_case = 0;
4823e12c5d1SDavid du Colombier }
4833e12c5d1SDavid du Colombier
4843e12c5d1SDavid du Colombier /* Arrange for convenient computation of quotients:
4853e12c5d1SDavid du Colombier * shift left if necessary so divisor has 4 leading 0 bits.
4863e12c5d1SDavid du Colombier *
4873e12c5d1SDavid du Colombier * Perhaps we should just compute leading 28 bits of S once
4883e12c5d1SDavid du Colombier * and for all and pass them and a shift to quorem, so it
4893e12c5d1SDavid du Colombier * can do shifts and ors to compute the numerator for q.
4903e12c5d1SDavid du Colombier */
4913e12c5d1SDavid du Colombier #ifdef Pack_32
4923e12c5d1SDavid du Colombier if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)
4933e12c5d1SDavid du Colombier i = 32 - i;
4943e12c5d1SDavid du Colombier #else
4953e12c5d1SDavid du Colombier if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
4963e12c5d1SDavid du Colombier i = 16 - i;
4973e12c5d1SDavid du Colombier #endif
4983e12c5d1SDavid du Colombier if (i > 4) {
4993e12c5d1SDavid du Colombier i -= 4;
5003e12c5d1SDavid du Colombier b2 += i;
5013e12c5d1SDavid du Colombier m2 += i;
5023e12c5d1SDavid du Colombier s2 += i;
5033e12c5d1SDavid du Colombier }
5043e12c5d1SDavid du Colombier else if (i < 4) {
5053e12c5d1SDavid du Colombier i += 28;
5063e12c5d1SDavid du Colombier b2 += i;
5073e12c5d1SDavid du Colombier m2 += i;
5083e12c5d1SDavid du Colombier s2 += i;
5093e12c5d1SDavid du Colombier }
5103e12c5d1SDavid du Colombier if (b2 > 0)
5113e12c5d1SDavid du Colombier b = lshift(b, b2);
5123e12c5d1SDavid du Colombier if (s2 > 0)
5133e12c5d1SDavid du Colombier S = lshift(S, s2);
5143e12c5d1SDavid du Colombier if (k_check) {
5153e12c5d1SDavid du Colombier if (cmp(b,S) < 0) {
5163e12c5d1SDavid du Colombier k--;
5173e12c5d1SDavid du Colombier b = multadd(b, 10, 0); /* we botched the k estimate */
5183e12c5d1SDavid du Colombier if (leftright)
5193e12c5d1SDavid du Colombier mhi = multadd(mhi, 10, 0);
5203e12c5d1SDavid du Colombier ilim = ilim1;
5213e12c5d1SDavid du Colombier }
5223e12c5d1SDavid du Colombier }
5233e12c5d1SDavid du Colombier if (ilim <= 0 && mode > 2) {
5243e12c5d1SDavid du Colombier if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
5253e12c5d1SDavid du Colombier /* no digits, fcvt style */
5263e12c5d1SDavid du Colombier no_digits:
5273e12c5d1SDavid du Colombier k = -1 - ndigits;
5283e12c5d1SDavid du Colombier goto ret;
5293e12c5d1SDavid du Colombier }
5303e12c5d1SDavid du Colombier one_digit:
5313e12c5d1SDavid du Colombier *s++ = '1';
5323e12c5d1SDavid du Colombier k++;
5333e12c5d1SDavid du Colombier goto ret;
5343e12c5d1SDavid du Colombier }
5353e12c5d1SDavid du Colombier if (leftright) {
5363e12c5d1SDavid du Colombier if (m2 > 0)
5373e12c5d1SDavid du Colombier mhi = lshift(mhi, m2);
5383e12c5d1SDavid du Colombier
5393e12c5d1SDavid du Colombier /* Compute mlo -- check for special case
5403e12c5d1SDavid du Colombier * that d is a normalized power of 2.
5413e12c5d1SDavid du Colombier */
5423e12c5d1SDavid du Colombier
5433e12c5d1SDavid du Colombier mlo = mhi;
5443e12c5d1SDavid du Colombier if (spec_case) {
5453e12c5d1SDavid du Colombier mhi = Balloc(mhi->k);
5463e12c5d1SDavid du Colombier Bcopy(mhi, mlo);
5473e12c5d1SDavid du Colombier mhi = lshift(mhi, Log2P);
5483e12c5d1SDavid du Colombier }
5493e12c5d1SDavid du Colombier
5503e12c5d1SDavid du Colombier for(i = 1;;i++) {
5513e12c5d1SDavid du Colombier dig = quorem(b,S) + '0';
5523e12c5d1SDavid du Colombier /* Do we yet have the shortest decimal string
5533e12c5d1SDavid du Colombier * that will round to d?
5543e12c5d1SDavid du Colombier */
5553e12c5d1SDavid du Colombier j = cmp(b, mlo);
5563e12c5d1SDavid du Colombier delta = diff(S, mhi);
5573e12c5d1SDavid du Colombier j1 = delta->sign ? 1 : cmp(b, delta);
5583e12c5d1SDavid du Colombier Bfree(delta);
5593e12c5d1SDavid du Colombier #ifndef ROUND_BIASED
5603e12c5d1SDavid du Colombier if (j1 == 0 && !mode && !(word1(d) & 1)) {
5613e12c5d1SDavid du Colombier if (dig == '9')
5623e12c5d1SDavid du Colombier goto round_9_up;
5633e12c5d1SDavid du Colombier if (j > 0)
5643e12c5d1SDavid du Colombier dig++;
5653e12c5d1SDavid du Colombier *s++ = dig;
5663e12c5d1SDavid du Colombier goto ret;
5673e12c5d1SDavid du Colombier }
5683e12c5d1SDavid du Colombier #endif
5693e12c5d1SDavid du Colombier if (j < 0 || j == 0 && !mode
5703e12c5d1SDavid du Colombier #ifndef ROUND_BIASED
5713e12c5d1SDavid du Colombier && !(word1(d) & 1)
5723e12c5d1SDavid du Colombier #endif
5733e12c5d1SDavid du Colombier ) {
5743e12c5d1SDavid du Colombier if (j1 > 0) {
5753e12c5d1SDavid du Colombier b = lshift(b, 1);
5763e12c5d1SDavid du Colombier j1 = cmp(b, S);
5773e12c5d1SDavid du Colombier if ((j1 > 0 || j1 == 0 && dig & 1)
5783e12c5d1SDavid du Colombier && dig++ == '9')
5793e12c5d1SDavid du Colombier goto round_9_up;
5803e12c5d1SDavid du Colombier }
5813e12c5d1SDavid du Colombier *s++ = dig;
5823e12c5d1SDavid du Colombier goto ret;
5833e12c5d1SDavid du Colombier }
5843e12c5d1SDavid du Colombier if (j1 > 0) {
5853e12c5d1SDavid du Colombier if (dig == '9') { /* possible if i == 1 */
5863e12c5d1SDavid du Colombier round_9_up:
5873e12c5d1SDavid du Colombier *s++ = '9';
5883e12c5d1SDavid du Colombier goto roundoff;
5893e12c5d1SDavid du Colombier }
5903e12c5d1SDavid du Colombier *s++ = dig + 1;
5913e12c5d1SDavid du Colombier goto ret;
5923e12c5d1SDavid du Colombier }
5933e12c5d1SDavid du Colombier *s++ = dig;
5943e12c5d1SDavid du Colombier if (i == ilim)
5953e12c5d1SDavid du Colombier break;
5963e12c5d1SDavid du Colombier b = multadd(b, 10, 0);
5973e12c5d1SDavid du Colombier if (mlo == mhi)
5983e12c5d1SDavid du Colombier mlo = mhi = multadd(mhi, 10, 0);
5993e12c5d1SDavid du Colombier else {
6003e12c5d1SDavid du Colombier mlo = multadd(mlo, 10, 0);
6013e12c5d1SDavid du Colombier mhi = multadd(mhi, 10, 0);
6023e12c5d1SDavid du Colombier }
6033e12c5d1SDavid du Colombier }
6043e12c5d1SDavid du Colombier }
6053e12c5d1SDavid du Colombier else
6063e12c5d1SDavid du Colombier for(i = 1;; i++) {
6073e12c5d1SDavid du Colombier *s++ = dig = quorem(b,S) + '0';
6083e12c5d1SDavid du Colombier if (i >= ilim)
6093e12c5d1SDavid du Colombier break;
6103e12c5d1SDavid du Colombier b = multadd(b, 10, 0);
6113e12c5d1SDavid du Colombier }
6123e12c5d1SDavid du Colombier
6133e12c5d1SDavid du Colombier /* Round off last digit */
6143e12c5d1SDavid du Colombier
6153e12c5d1SDavid du Colombier b = lshift(b, 1);
6163e12c5d1SDavid du Colombier j = cmp(b, S);
6173e12c5d1SDavid du Colombier if (j > 0 || j == 0 && dig & 1) {
6183e12c5d1SDavid du Colombier roundoff:
6193e12c5d1SDavid du Colombier while(*--s == '9')
6203e12c5d1SDavid du Colombier if (s == s0) {
6213e12c5d1SDavid du Colombier k++;
6223e12c5d1SDavid du Colombier *s++ = '1';
6233e12c5d1SDavid du Colombier goto ret;
6243e12c5d1SDavid du Colombier }
6253e12c5d1SDavid du Colombier ++*s++;
6263e12c5d1SDavid du Colombier }
6273e12c5d1SDavid du Colombier else {
6283e12c5d1SDavid du Colombier while(*--s == '0');
6293e12c5d1SDavid du Colombier s++;
6303e12c5d1SDavid du Colombier }
6313e12c5d1SDavid du Colombier ret:
6323e12c5d1SDavid du Colombier Bfree(S);
6333e12c5d1SDavid du Colombier if (mhi) {
6343e12c5d1SDavid du Colombier if (mlo && mlo != mhi)
6353e12c5d1SDavid du Colombier Bfree(mlo);
6363e12c5d1SDavid du Colombier Bfree(mhi);
6373e12c5d1SDavid du Colombier }
6383e12c5d1SDavid du Colombier ret1:
6393e12c5d1SDavid du Colombier Bfree(b);
6403e12c5d1SDavid du Colombier *s = 0;
6413e12c5d1SDavid du Colombier *decpt = k + 1;
6423e12c5d1SDavid du Colombier if (rve)
6433e12c5d1SDavid du Colombier *rve = s;
6443e12c5d1SDavid du Colombier return s0;
6453e12c5d1SDavid du Colombier }
6463e12c5d1SDavid du Colombier
6473e12c5d1SDavid du Colombier static int
quorem(Bigint * b,Bigint * S)6483e12c5d1SDavid du Colombier quorem(Bigint *b, Bigint *S)
6493e12c5d1SDavid du Colombier {
6503e12c5d1SDavid du Colombier int n;
6513e12c5d1SDavid du Colombier long borrow, y;
6523e12c5d1SDavid du Colombier unsigned long carry, q, ys;
6533e12c5d1SDavid du Colombier unsigned long *bx, *bxe, *sx, *sxe;
6543e12c5d1SDavid du Colombier #ifdef Pack_32
6553e12c5d1SDavid du Colombier long z;
6563e12c5d1SDavid du Colombier unsigned long si, zs;
6573e12c5d1SDavid du Colombier #endif
6583e12c5d1SDavid du Colombier
6593e12c5d1SDavid du Colombier n = S->wds;
6603e12c5d1SDavid du Colombier #ifdef DEBUG
6613e12c5d1SDavid du Colombier /*debug*/ if (b->wds > n)
6623e12c5d1SDavid du Colombier /*debug*/ Bug("oversize b in quorem");
6633e12c5d1SDavid du Colombier #endif
6643e12c5d1SDavid du Colombier if (b->wds < n)
6653e12c5d1SDavid du Colombier return 0;
6663e12c5d1SDavid du Colombier sx = S->x;
6673e12c5d1SDavid du Colombier sxe = sx + --n;
6683e12c5d1SDavid du Colombier bx = b->x;
6693e12c5d1SDavid du Colombier bxe = bx + n;
6703e12c5d1SDavid du Colombier q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
6713e12c5d1SDavid du Colombier #ifdef DEBUG
6723e12c5d1SDavid du Colombier /*debug*/ if (q > 9)
6733e12c5d1SDavid du Colombier /*debug*/ Bug("oversized quotient in quorem");
6743e12c5d1SDavid du Colombier #endif
6753e12c5d1SDavid du Colombier if (q) {
6763e12c5d1SDavid du Colombier borrow = 0;
6773e12c5d1SDavid du Colombier carry = 0;
6783e12c5d1SDavid du Colombier do {
6793e12c5d1SDavid du Colombier #ifdef Pack_32
6803e12c5d1SDavid du Colombier si = *sx++;
6813e12c5d1SDavid du Colombier ys = (si & 0xffff) * q + carry;
6823e12c5d1SDavid du Colombier zs = (si >> 16) * q + (ys >> 16);
6833e12c5d1SDavid du Colombier carry = zs >> 16;
6843e12c5d1SDavid du Colombier y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
6853e12c5d1SDavid du Colombier borrow = y >> 16;
6863e12c5d1SDavid du Colombier Sign_Extend(borrow, y);
6873e12c5d1SDavid du Colombier z = (*bx >> 16) - (zs & 0xffff) + borrow;
6883e12c5d1SDavid du Colombier borrow = z >> 16;
6893e12c5d1SDavid du Colombier Sign_Extend(borrow, z);
6903e12c5d1SDavid du Colombier Storeinc(bx, z, y);
6913e12c5d1SDavid du Colombier #else
6923e12c5d1SDavid du Colombier ys = *sx++ * q + carry;
6933e12c5d1SDavid du Colombier carry = ys >> 16;
6943e12c5d1SDavid du Colombier y = *bx - (ys & 0xffff) + borrow;
6953e12c5d1SDavid du Colombier borrow = y >> 16;
6963e12c5d1SDavid du Colombier Sign_Extend(borrow, y);
6973e12c5d1SDavid du Colombier *bx++ = y & 0xffff;
6983e12c5d1SDavid du Colombier #endif
6993e12c5d1SDavid du Colombier }
7003e12c5d1SDavid du Colombier while(sx <= sxe);
7013e12c5d1SDavid du Colombier if (!*bxe) {
7023e12c5d1SDavid du Colombier bx = b->x;
7033e12c5d1SDavid du Colombier while(--bxe > bx && !*bxe)
7043e12c5d1SDavid du Colombier --n;
7053e12c5d1SDavid du Colombier b->wds = n;
7063e12c5d1SDavid du Colombier }
7073e12c5d1SDavid du Colombier }
7083e12c5d1SDavid du Colombier if (cmp(b, S) >= 0) {
7093e12c5d1SDavid du Colombier q++;
7103e12c5d1SDavid du Colombier borrow = 0;
7113e12c5d1SDavid du Colombier carry = 0;
7123e12c5d1SDavid du Colombier bx = b->x;
7133e12c5d1SDavid du Colombier sx = S->x;
7143e12c5d1SDavid du Colombier do {
7153e12c5d1SDavid du Colombier #ifdef Pack_32
7163e12c5d1SDavid du Colombier si = *sx++;
7173e12c5d1SDavid du Colombier ys = (si & 0xffff) + carry;
7183e12c5d1SDavid du Colombier zs = (si >> 16) + (ys >> 16);
7193e12c5d1SDavid du Colombier carry = zs >> 16;
7203e12c5d1SDavid du Colombier y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
7213e12c5d1SDavid du Colombier borrow = y >> 16;
7223e12c5d1SDavid du Colombier Sign_Extend(borrow, y);
7233e12c5d1SDavid du Colombier z = (*bx >> 16) - (zs & 0xffff) + borrow;
7243e12c5d1SDavid du Colombier borrow = z >> 16;
7253e12c5d1SDavid du Colombier Sign_Extend(borrow, z);
7263e12c5d1SDavid du Colombier Storeinc(bx, z, y);
7273e12c5d1SDavid du Colombier #else
7283e12c5d1SDavid du Colombier ys = *sx++ + carry;
7293e12c5d1SDavid du Colombier carry = ys >> 16;
7303e12c5d1SDavid du Colombier y = *bx - (ys & 0xffff) + borrow;
7313e12c5d1SDavid du Colombier borrow = y >> 16;
7323e12c5d1SDavid du Colombier Sign_Extend(borrow, y);
7333e12c5d1SDavid du Colombier *bx++ = y & 0xffff;
7343e12c5d1SDavid du Colombier #endif
7353e12c5d1SDavid du Colombier }
7363e12c5d1SDavid du Colombier while(sx <= sxe);
7373e12c5d1SDavid du Colombier bx = b->x;
7383e12c5d1SDavid du Colombier bxe = bx + n;
7393e12c5d1SDavid du Colombier if (!*bxe) {
7403e12c5d1SDavid du Colombier while(--bxe > bx && !*bxe)
7413e12c5d1SDavid du Colombier --n;
7423e12c5d1SDavid du Colombier b->wds = n;
7433e12c5d1SDavid du Colombier }
7443e12c5d1SDavid du Colombier }
7453e12c5d1SDavid du Colombier return q;
7463e12c5d1SDavid du Colombier }
747