| /* 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); |
| */ |
| } |