| /* Free-format floating point printer | 
 |  *  | 
 |  * Based on "Floating-Point Printer Sample Code", by Robert G. Burger, | 
 |  * http://www.cs.indiana.edu/~burger/fp/index.html | 
 |  */ | 
 |  | 
 | #include "Python.h" | 
 |  | 
 | #if defined(__alpha) || defined(__i386) || defined(_M_IX86) || defined(_M_X64) || defined(_M_IA64) | 
 | #define LITTLE_ENDIAN_IEEE_DOUBLE | 
 | #elif !(defined(__ppc__) || defined(sparc) || defined(__sgi) || defined(_IBMR2) || defined(hpux)) | 
 | #error unknown machine type | 
 | #endif | 
 |  | 
 | #if defined(_M_IX86) | 
 | #define UNSIGNED64 unsigned __int64 | 
 | #elif defined(__alpha) | 
 | #define UNSIGNED64 unsigned long | 
 | #else | 
 | #define UNSIGNED64 unsigned long long | 
 | #endif | 
 |  | 
 | #ifndef U32 | 
 | #define U32 unsigned int | 
 | #endif | 
 |  | 
 | /* exponent stored + 1024, hidden bit to left of decimal point */ | 
 | #define bias 1023 | 
 | #define bitstoright 52 | 
 | #define m1mask 0xf | 
 | #define hidden_bit 0x100000 | 
 | #ifdef LITTLE_ENDIAN_IEEE_DOUBLE | 
 | struct dblflt { | 
 |     unsigned int m4: 16; | 
 |     unsigned int m3: 16; | 
 |     unsigned int m2: 16; | 
 |     unsigned int m1: 4; | 
 |     unsigned int e: 11; | 
 |     unsigned int s: 1; | 
 | }; | 
 | #else | 
 | /* Big Endian IEEE Double Floats */ | 
 | struct dblflt { | 
 |     unsigned int s: 1; | 
 |     unsigned int e: 11; | 
 |     unsigned int m1: 4; | 
 |     unsigned int m2: 16; | 
 |     unsigned int m3: 16; | 
 |     unsigned int m4: 16; | 
 | }; | 
 | #endif | 
 | #define float_radix 2.147483648e9 | 
 |  | 
 |  | 
 | typedef UNSIGNED64 Bigit; | 
 | #define BIGSIZE 24 | 
 | #define MIN_E -1074 | 
 | #define MAX_FIVE 325 | 
 | #define B_P1 ((Bigit)1 << 52) | 
 |  | 
 | typedef struct { | 
 |    int l; | 
 |    Bigit d[BIGSIZE]; | 
 | } Bignum; | 
 |  | 
 | static Bignum R, S, MP, MM, five[MAX_FIVE]; | 
 | static Bignum S2, S3, S4, S5, S6, S7, S8, S9; | 
 | static int ruf, k, s_n, use_mp, qr_shift, sl, slr; | 
 |  | 
 | static void mul10(Bignum *x); | 
 | static void big_short_mul(Bignum *x, Bigit y, Bignum *z); | 
 | /* | 
 | static void print_big(Bignum *x); | 
 | */ | 
 | static int estimate(int n); | 
 | static void one_shift_left(int y, Bignum *z); | 
 | static void short_shift_left(Bigit x, int y, Bignum *z); | 
 | static void big_shift_left(Bignum *x, int y, Bignum *z); | 
 | static int big_comp(Bignum *x, Bignum *y); | 
 | static int sub_big(Bignum *x, Bignum *y, Bignum *z); | 
 | static void add_big(Bignum *x, Bignum *y, Bignum *z); | 
 | static int add_cmp(void); | 
 | static int qr(void); | 
 |  | 
 | /*static int _PyFloat_Digits(char *buf, double v, int *signum);*/ | 
 | /*static void _PyFloat_DigitsInit(void);*/ | 
 |  | 
 | #define ADD(x, y, z, k) {\ | 
 |    Bigit x_add, z_add;\ | 
 |    x_add = (x);\ | 
 |    if ((k))\ | 
 |      z_add = x_add + (y) + 1, (k) = (z_add <= x_add);\ | 
 |    else\ | 
 |      z_add = x_add + (y), (k) = (z_add < x_add);\ | 
 |    (z) = z_add;\ | 
 | } | 
 |  | 
 | #define SUB(x, y, z, b) {\ | 
 |    Bigit x_sub, y_sub;\ | 
 |    x_sub = (x); y_sub = (y);\ | 
 |    if ((b))\ | 
 |      (z) = x_sub - y_sub - 1, b = (y_sub >= x_sub);\ | 
 |    else\ | 
 |      (z) = x_sub - y_sub, b = (y_sub > x_sub);\ | 
 | } | 
 |  | 
 | #define MUL(x, y, z, k) {\ | 
 |    Bigit x_mul, low, high;\ | 
 |    x_mul = (x);\ | 
 |    low = (x_mul & 0xffffffff) * (y) + (k);\ | 
 |    high = (x_mul >> 32) * (y) + (low >> 32);\ | 
 |    (k) = high >> 32;\ | 
 |    (z) = (low & 0xffffffff) | (high << 32);\ | 
 | } | 
 |  | 
 | #define SLL(x, y, z, k) {\ | 
 |    Bigit x_sll = (x);\ | 
 |    (z) = (x_sll << (y)) | (k);\ | 
 |    (k) = x_sll >> (64 - (y));\ | 
 | } | 
 |  | 
 | static void | 
 | mul10(Bignum *x) | 
 | { | 
 |    int i, l; | 
 |    Bigit *p, k; | 
 |  | 
 |    l = x->l; | 
 |    for (i = l, p = &x->d[0], k = 0; i >= 0; i--) | 
 |       MUL(*p, 10, *p++, k); | 
 |    if (k != 0) | 
 |       *p = k, x->l = l+1; | 
 | } | 
 |  | 
 | static void | 
 | big_short_mul(Bignum *x, Bigit y, Bignum *z) | 
 | { | 
 |    int i, xl, zl; | 
 |    Bigit *xp, *zp, k; | 
 |    U32 high, low; | 
 |  | 
 |    xl = x->l; | 
 |    xp = &x->d[0]; | 
 |    zl = xl; | 
 |    zp = &z->d[0]; | 
 |    high = y >> 32; | 
 |    low = y & 0xffffffff; | 
 |    for (i = xl, k = 0; i >= 0; i--, xp++, zp++) { | 
 |       Bigit xlow, xhigh, z0, t, c, z1; | 
 |       xlow = *xp & 0xffffffff; | 
 |       xhigh = *xp >> 32; | 
 |       z0 = (xlow * low) + k; /* Cout is (z0 < k) */ | 
 |       t = xhigh * low; | 
 |       z1 = (xlow * high) + t; | 
 |       c = (z1 < t); | 
 |       t = z0 >> 32; | 
 |       z1 += t; | 
 |       c += (z1 < t); | 
 |       *zp = (z1 << 32) | (z0 & 0xffffffff); | 
 |       k = (xhigh * high) + (c << 32) + (z1 >> 32) + (z0 < k); | 
 |    } | 
 |    if (k != 0) | 
 |       *zp = k, zl++; | 
 |    z->l = zl; | 
 | } | 
 |  | 
 | /* | 
 | static void | 
 | print_big(Bignum *x) | 
 | { | 
 |    int i; | 
 |    Bigit *p; | 
 |  | 
 |    printf("#x"); | 
 |    i = x->l; | 
 |    p = &x->d[i]; | 
 |    for (p = &x->d[i]; i >= 0; i--) { | 
 |       Bigit b = *p--; | 
 |       printf("%08x%08x", (int)(b >> 32), (int)(b & 0xffffffff)); | 
 |    } | 
 | } | 
 | */ | 
 |  | 
 | static int | 
 | estimate(int n) | 
 | { | 
 |    if (n < 0) | 
 |       return (int)(n*0.3010299956639812); | 
 |    else | 
 |       return 1+(int)(n*0.3010299956639811); | 
 | } | 
 |  | 
 | static void | 
 | one_shift_left(int y, Bignum *z) | 
 | { | 
 |    int n, m, i; | 
 |    Bigit *zp; | 
 |  | 
 |    n = y / 64; | 
 |    m = y % 64; | 
 |    zp = &z->d[0]; | 
 |    for (i = n; i > 0; i--) *zp++ = 0; | 
 |    *zp = (Bigit)1 << m; | 
 |    z->l = n; | 
 | } | 
 |  | 
 | static void | 
 | short_shift_left(Bigit x, int y, Bignum *z) | 
 | { | 
 |    int n, m, i, zl; | 
 |    Bigit *zp; | 
 |     | 
 |    n = y / 64; | 
 |    m = y % 64; | 
 |    zl = n; | 
 |    zp = &(z->d[0]); | 
 |    for (i = n; i > 0; i--) *zp++ = 0; | 
 |    if (m == 0) | 
 |       *zp = x; | 
 |    else { | 
 |       Bigit high = x >> (64 - m); | 
 |       *zp = x << m; | 
 |       if (high != 0) | 
 |          *++zp = high, zl++; | 
 |    } | 
 |    z->l = zl; | 
 | } | 
 |  | 
 | static void | 
 | big_shift_left(Bignum *x, int y, Bignum *z) | 
 | { | 
 |    int n, m, i, xl, zl; | 
 |    Bigit *xp, *zp, k; | 
 |     | 
 |    n = y / 64; | 
 |    m = y % 64; | 
 |    xl = x->l; | 
 |    xp = &(x->d[0]); | 
 |    zl = xl + n; | 
 |    zp = &(z->d[0]); | 
 |    for (i = n; i > 0; i--) *zp++ = 0; | 
 |    if (m == 0) | 
 |       for (i = xl; i >= 0; i--) *zp++ = *xp++; | 
 |    else { | 
 |       for (i = xl, k = 0; i >= 0; i--) | 
 |          SLL(*xp++, m, *zp++, k); | 
 |       if (k != 0) | 
 |          *zp = k, zl++; | 
 |    } | 
 |    z->l = zl; | 
 | } | 
 |  | 
 |  | 
 | static int | 
 | big_comp(Bignum *x, Bignum *y) | 
 | { | 
 |    int i, xl, yl; | 
 |    Bigit *xp, *yp; | 
 |  | 
 |    xl = x->l; | 
 |    yl = y->l; | 
 |    if (xl > yl) return 1; | 
 |    if (xl < yl) return -1; | 
 |    xp = &x->d[xl]; | 
 |    yp = &y->d[xl]; | 
 |    for (i = xl; i >= 0; i--, xp--, yp--) { | 
 |       Bigit a = *xp; | 
 |       Bigit b = *yp; | 
 |  | 
 |       if (a > b) return 1; | 
 |       else if (a < b) return -1; | 
 |    } | 
 |    return 0; | 
 | } | 
 |  | 
 | static int | 
 | sub_big(Bignum *x, Bignum *y, Bignum *z) | 
 | { | 
 |   int xl, yl, zl, b, i; | 
 |   Bigit *xp, *yp, *zp; | 
 |  | 
 |   xl = x->l; | 
 |   yl = y->l; | 
 |   if (yl > xl) return 1; | 
 |   xp = &x->d[0]; | 
 |   yp = &y->d[0]; | 
 |   zp = &z->d[0]; | 
 |    | 
 |   for (i = yl, b = 0; i >= 0; i--) | 
 |     SUB(*xp++, *yp++, *zp++, b); | 
 |   for (i = xl-yl; b && i > 0; i--) { | 
 |     Bigit x_sub; | 
 |     x_sub = *xp++; | 
 |     *zp++ = x_sub - 1; | 
 |     b = (x_sub == 0); | 
 |   } | 
 |   for (; i > 0; i--) *zp++ = *xp++; | 
 |   if (b) return 1; | 
 |   zl = xl; | 
 |   while (*--zp == 0) zl--; | 
 |   z->l = zl; | 
 |   return 0; | 
 | } | 
 |  | 
 | static void | 
 | add_big(Bignum *x, Bignum *y, Bignum *z) | 
 | { | 
 |   int xl, yl, k, i; | 
 |   Bigit *xp, *yp, *zp; | 
 |  | 
 |   xl = x->l; | 
 |   yl = y->l; | 
 |   if (yl > xl) { | 
 |     int tl; | 
 |     Bignum *tn; | 
 |     tl = xl; xl = yl; yl = tl; | 
 |     tn = x; x = y; y = tn; | 
 |   } | 
 |  | 
 |   xp = &x->d[0]; | 
 |   yp = &y->d[0]; | 
 |   zp = &z->d[0]; | 
 |    | 
 |   for (i = yl, k = 0; i >= 0; i--) | 
 |     ADD(*xp++, *yp++, *zp++, k); | 
 |   for (i = xl-yl; k && i > 0; i--) { | 
 |     Bigit z_add; | 
 |     z_add = *xp++ + 1; | 
 |     k = (z_add == 0); | 
 |     *zp++ = z_add; | 
 |   } | 
 |   for (; i > 0; i--) *zp++ = *xp++; | 
 |   if (k) | 
 |     *zp = 1, z->l = xl+1; | 
 |   else | 
 |     z->l = xl; | 
 | } | 
 |  | 
 | static int | 
 | add_cmp() | 
 | { | 
 |    int rl, ml, sl, suml; | 
 |    static Bignum sum; | 
 |  | 
 |    rl = R.l; | 
 |    ml = (use_mp ? MP.l : MM.l); | 
 |    sl = S.l; | 
 |     | 
 |    suml = rl >= ml ? rl : ml; | 
 |    if ((sl > suml+1) || ((sl == suml+1) && (S.d[sl] > 1))) return -1; | 
 |    if (sl < suml) return 1; | 
 |  | 
 |    add_big(&R, (use_mp ? &MP : &MM), &sum); | 
 |    return big_comp(&sum, &S); | 
 | } | 
 |  | 
 | static int | 
 | qr() | 
 | { | 
 |   if (big_comp(&R, &S5) < 0) | 
 |     if (big_comp(&R, &S2) < 0) | 
 |       if (big_comp(&R, &S) < 0) | 
 |         return 0; | 
 |       else { | 
 |         sub_big(&R, &S, &R); | 
 |         return 1; | 
 |       } | 
 |     else if (big_comp(&R, &S3) < 0) { | 
 |       sub_big(&R, &S2, &R); | 
 |       return 2; | 
 |     } | 
 |     else if (big_comp(&R, &S4) < 0) { | 
 |       sub_big(&R, &S3, &R); | 
 |       return 3; | 
 |     } | 
 |     else { | 
 |       sub_big(&R, &S4, &R); | 
 |       return 4; | 
 |     } | 
 |   else if (big_comp(&R, &S7) < 0) | 
 |     if (big_comp(&R, &S6) < 0) { | 
 |       sub_big(&R, &S5, &R); | 
 |       return 5; | 
 |     } | 
 |     else { | 
 |       sub_big(&R, &S6, &R); | 
 |       return 6; | 
 |     } | 
 |   else if (big_comp(&R, &S9) < 0) | 
 |     if (big_comp(&R, &S8) < 0) { | 
 |       sub_big(&R, &S7, &R); | 
 |       return 7; | 
 |     } | 
 |     else { | 
 |       sub_big(&R, &S8, &R); | 
 |       return 8; | 
 |     } | 
 |   else { | 
 |     sub_big(&R, &S9, &R); | 
 |     return 9; | 
 |   } | 
 | } | 
 |  | 
 | #define OUTDIG(d) { *buf++ = (d) + '0'; *buf = 0; return k; } | 
 |  | 
 | int | 
 | _PyFloat_Digits(char *buf, double v, int *signum) | 
 | { | 
 |    struct dblflt *x; | 
 |    int sign, e, f_n, m_n, i, d, tc1, tc2; | 
 |    Bigit f; | 
 |  | 
 |    /* decompose float into sign, mantissa & exponent */ | 
 |    x = (struct dblflt *)&v; | 
 |    sign = x->s; | 
 |    e = x->e;  | 
 |    f = (Bigit)(x->m1 << 16 | x->m2) << 32 | (U32)(x->m3 << 16 | x->m4); | 
 |    if (e != 0) { | 
 |       e = e - bias - bitstoright; | 
 |       f |= (Bigit)hidden_bit << 32; | 
 |    } | 
 |    else if (f != 0) | 
 |       /* denormalized */ | 
 |       e = 1 - bias - bitstoright; | 
 |  | 
 |    *signum = sign; | 
 |    if (f == 0) { | 
 |      *buf++ = '0'; | 
 |      *buf = 0; | 
 |      return 0; | 
 |    } | 
 |     | 
 |    ruf = !(f & 1); /* ruf = (even? f) */ | 
 |  | 
 |    /* Compute the scaling factor estimate, k */ | 
 |    if (e > MIN_E) | 
 |       k = estimate(e+52); | 
 |    else { | 
 |       int n; | 
 |       Bigit y; | 
 |        | 
 |       for (n = e+52, y = (Bigit)1 << 52; f < y; n--) y >>= 1; | 
 |       k = estimate(n); | 
 |    } | 
 |  | 
 |    if (e >= 0) | 
 |       if (f != B_P1) | 
 |          use_mp = 0, f_n = e+1, s_n = 1, m_n = e; | 
 |       else | 
 |          use_mp = 1, f_n = e+2, s_n = 2, m_n = e; | 
 |    else | 
 |       if ((e == MIN_E) || (f != B_P1)) | 
 |          use_mp = 0, f_n = 1, s_n = 1-e, m_n = 0; | 
 |       else | 
 |          use_mp = 1, f_n = 2, s_n = 2-e, m_n = 0; | 
 |     | 
 |    /* Scale it! */ | 
 |    if (k == 0) { | 
 |       short_shift_left(f, f_n, &R); | 
 |       one_shift_left(s_n, &S); | 
 |       one_shift_left(m_n, &MM); | 
 |       if (use_mp) one_shift_left(m_n+1, &MP); | 
 |       qr_shift = 1; | 
 |    } | 
 |    else if (k > 0) { | 
 |       s_n += k; | 
 |       if (m_n >= s_n) | 
 |          f_n -= s_n, m_n -= s_n, s_n = 0; | 
 |       else  | 
 |          f_n -= m_n, s_n -= m_n, m_n = 0; | 
 |       short_shift_left(f, f_n, &R); | 
 |       big_shift_left(&five[k-1], s_n, &S); | 
 |       one_shift_left(m_n, &MM); | 
 |       if (use_mp) one_shift_left(m_n+1, &MP); | 
 |       qr_shift = 0; | 
 |    } | 
 |    else { | 
 |       Bignum *power = &five[-k-1]; | 
 |  | 
 |       s_n += k; | 
 |       big_short_mul(power, f, &S); | 
 |       big_shift_left(&S, f_n, &R); | 
 |       one_shift_left(s_n, &S); | 
 |       big_shift_left(power, m_n, &MM); | 
 |       if (use_mp) big_shift_left(power, m_n+1, &MP); | 
 |       qr_shift = 1; | 
 |    } | 
 |  | 
 |    /* fixup */ | 
 |    if (add_cmp() <= -ruf) { | 
 |      k--; | 
 |      mul10(&R); | 
 |      mul10(&MM); | 
 |      if (use_mp) mul10(&MP); | 
 |    } | 
 |  | 
 |    /* | 
 |    printf("\nk = %d\n", k); | 
 |    printf("R = "); print_big(&R); | 
 |    printf("\nS = "); print_big(&S); | 
 |    printf("\nM- = "); print_big(&MM); | 
 |    if (use_mp) printf("\nM+ = "), print_big(&MP); | 
 |    putchar('\n'); | 
 |    fflush(0); | 
 |    */ | 
 |     | 
 |    if (qr_shift) { | 
 |      sl = s_n / 64; | 
 |      slr = s_n % 64; | 
 |    } | 
 |    else { | 
 |      big_shift_left(&S, 1, &S2); | 
 |      add_big(&S2, &S, &S3); | 
 |      big_shift_left(&S2, 1, &S4); | 
 |      add_big(&S4, &S, &S5); | 
 |      add_big(&S4, &S2, &S6); | 
 |      add_big(&S4, &S3, &S7); | 
 |      big_shift_left(&S4, 1, &S8); | 
 |      add_big(&S8, &S, &S9); | 
 |    } | 
 |  | 
 | again: | 
 |    if (qr_shift) { /* Take advantage of the fact that S = (ash 1 s_n) */ | 
 |       if (R.l < sl) | 
 |          d = 0; | 
 |       else if (R.l == sl) { | 
 |             Bigit *p; | 
 |  | 
 |             p = &R.d[sl]; | 
 |             d = *p >> slr; | 
 |             *p &= ((Bigit)1 << slr) - 1; | 
 |             for (i = sl; (i > 0) && (*p == 0); i--) p--; | 
 |             R.l = i; | 
 |          } | 
 |       else { | 
 |          Bigit *p; | 
 |           | 
 |          p = &R.d[sl+1]; | 
 |          d = *p << (64 - slr) | *(p-1) >> slr; | 
 |          p--; | 
 |          *p &= ((Bigit)1 << slr) - 1; | 
 |          for (i = sl; (i > 0) && (*p == 0); i--) p--; | 
 |          R.l = i; | 
 |       } | 
 |    } | 
 |    else /* We need to do quotient-remainder */ | 
 |      d = qr(); | 
 |  | 
 |    tc1 = big_comp(&R, &MM) < ruf; | 
 |    tc2 = add_cmp() > -ruf; | 
 |    if (!tc1) | 
 |       if (!tc2) { | 
 |          mul10(&R); | 
 |          mul10(&MM); | 
 |          if (use_mp) mul10(&MP); | 
 |          *buf++ = d + '0'; | 
 |          goto again; | 
 |       } | 
 |       else | 
 |         OUTDIG(d+1) | 
 |    else | 
 |       if (!tc2) | 
 |          OUTDIG(d) | 
 |       else { | 
 |          big_shift_left(&R, 1, &MM); | 
 |          if (big_comp(&MM, &S) == -1) | 
 |             OUTDIG(d) | 
 |          else | 
 |             OUTDIG(d+1) | 
 |       } | 
 | } | 
 |  | 
 | void | 
 | _PyFloat_DigitsInit() | 
 | { | 
 |    int n, i, l; | 
 |    Bignum *b; | 
 |    Bigit *xp, *zp, k; | 
 |  | 
 |    five[0].l = l = 0; | 
 |    five[0].d[0] = 5; | 
 |    for (n = MAX_FIVE-1, b = &five[0]; n > 0; n--) { | 
 |       xp = &b->d[0]; | 
 |       b++; | 
 |       zp = &b->d[0]; | 
 |       for (i = l, k = 0; i >= 0; i--) | 
 |          MUL(*xp++, 5, *zp++, k); | 
 |       if (k != 0) | 
 |          *zp = k, l++; | 
 |       b->l = l; | 
 |    } | 
 |  | 
 |    /* | 
 |    for (n = 1, b = &five[0]; n <= MAX_FIVE; n++) { | 
 |       big_shift_left(b++, n, &R); | 
 |       print_big(&R); | 
 |       putchar('\n'); | 
 |    } | 
 |    fflush(0); | 
 |    */ | 
 | } |