ref: fed50d79d38881437639f3189b4a99aee93daa9a
dir: /sys/src/libmp/port/mptod.c/
#include "os.h" #include <mp.h> #include "dat.h" double mptod(mpint *a) { u64int v; mpdigit w, r; int sf, i, n, m, s; FPdbleword x; if(a->top == 0) return 0.0; sf = mpsignif(a); if(sf > 1024) return Inf(a->sign); i = a->top - 1; v = a->p[i]; n = sf & Dbits - 1; n |= n - 1 & Dbits; r = 0; if(n > 54){ s = n - 54; r = v & (1<<s) - 1; v >>= s; } while(n < 54){ if(--i < 0) w = 0; else w = a->p[i]; m = 54 - n; if(m > Dbits) m = Dbits; s = Dbits - m & Dbits - 1; v = v << m | w >> s; r = w & (1<<s) - 1; n += m; } if((v & 3) == 1){ while(--i >= 0) r |= a->p[i]; if(r != 0) v++; }else v++; v >>= 1; while((v >> 53) != 0){ v >>= 1; if(++sf > 1024) return Inf(a->sign); } x.lo = v; x.hi = (u32int)(v >> 32) & (1<<20) - 1 | sf + 1022 << 20 | a->sign & 1<<31; return x.x; } mpint * dtomp(double d, mpint *a) { FPdbleword x; uvlong v; int e; if(a == nil) a = mpnew(0); x.x = d; e = x.hi >> 20 & 2047; assert(e != 2047); if(e < 1022){ mpassign(mpzero, a); return a; } v = x.lo | (uvlong)(x.hi & (1<<20) - 1) << 32 | 1ULL<<52; if(e < 1075){ v += (1ULL<<1074 - e) - (~v >> 1075 - e & 1); v >>= 1075 - e; } uvtomp(v, a); if(e > 1075) mpleft(a, e - 1075, a); if((int)x.hi < 0) a->sign = -1; return a; }