#include "cc.h" enum { Mpscale = 29, /* safely smaller than bits in a long */ Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */ Mpbase = 1L<= '0' && c <= '9') { ex = ex*10 + (c-'0'); continue; } break; } if(ef) ex = -ex; case 0: break; } break; } if(a.ovf) goto bad; if(zer) { *d = 0; return 0; } if(dp) dp--; dp -= ex; if(dp > 0) { /* * must divide by 10**dp */ if(mptof(&a, &d1)) goto bad; /* * trial exponent of 8**dp * 8 (being between 5 and 10) * should pick up all underflows * in the division of 5**dp. */ d2 = frexp(d1, &ex); d2 = ldexp(d2, ex-3*dp); if(d2 == 0) goto bad; /* * decompose each 10 into 5*2. * create 5**dp in fixed point * and then play with the exponent * for the remaining 2**dp. * note that 5**dp will overflow * with as few as 134 input digits. */ mpint(&a, 1); mppow(&a, 5, dp); if(mptof(&a, &d2)) goto bad; d1 = frexp(d1/d2, &ex); d1 = ldexp(d1, ex-dp); if(d1 == 0) goto bad; } else { /* * must multiply by 10**|dp| -- * just do it in fixed point. */ mppow(&a, 10, -dp); if(mptof(&a, &d1)) goto bad; } if(f) d1 = -d1; *d = d1; return 0; bad: return 1; } /* * convert a to floating in *d * return conversion overflow */ int mptof(Mp *a, double *d) { double f, g; long x, *a1; int i; if(a->ovf) return 1; a1 = a->a; f = ldexp(*a1++, 0); for(i=Mpscale; iovf) a->ovf = 1; if(a->ovf) return; c = 0; a1 = a->a; b1 = b->a; for(i=0; i= Mpbase) { x -= Mpbase; c = 1; } *a1++ = x; } a->ovf = c; } /* * return a = c */ void mpint(Mp *a, int c) { memset(a, 0, sizeof(*a)); a->a[0] = c; } /* * return a *= c */ void mpmul(Mp *a, int c) { Mp p; int b; memmove(&p, a, sizeof(p)); if(!(c & 1)) memset(a, 0, sizeof(*a)); c &= ~1; for(b=2; c; b<<=1) { mpadd(&p, &p); if(c & b) { mpadd(a, &p); c &= ~b; } } } /* * return a *= b**e */ void mppow(Mp *a, int b, int e) { int b1; b1 = b*b; b1 = b1*b1; while(e >= 4) { mpmul(a, b1); e -= 4; if(a->ovf) return; } while(e > 0) { mpmul(a, b); e--; } } /* * convert a string, s, to vlong in *v * return conversion overflow. * required syntax is [0[x]]d* */ int mpatov(char *s, vlong *v) { vlong n, nn; int c; n = 0; c = *s; if(c == '0') goto oct; while(c = *s++) { if(c >= '0' && c <= '9') nn = n*10 + c-'0'; else goto bad; if(n < 0 && nn >= 0) goto bad; n = nn; } goto out; oct: s++; c = *s; if(c == 'x' || c == 'X') goto hex; while(c = *s++) { if(c >= '0' || c <= '7') nn = n*8 + c-'0'; else goto bad; if(n < 0 && nn >= 0) goto bad; n = nn; } goto out; hex: s++; while(c = *s++) { if(c >= '0' && c <= '9') c += 0-'0'; else if(c >= 'a' && c <= 'f') c += 10-'a'; else if(c >= 'A' && c <= 'F') c += 10-'A'; else goto bad; nn = n*16 + c; if(n < 0 && nn >= 0) goto bad; n = nn; } out: *v = n; return 0; bad: *v = ~0; return 1; }