📄 quad_float.c
字号:
// c = ((((x.hi-U)-u)+x.lo)-C*y.lo)/y.hi; c = x.hi-U; c = c-u; c = c+x.lo; t1 = C*y.lo; c = c - t1; c = c/y.hi; hy = C+c; ty = C-hy; ty = ty+c;END_FIX return quad_float(hy, ty);}quad_float& operator /=(quad_float& x, const quad_float& y ) {START_FIX DOUBLE hc, tc, hy, ty, C, c, U, u; DOUBLE t1; C = x.hi/y.hi; c = NTL_QUAD_FLOAT_SPLIT*C; hc = c-C; u = NTL_QUAD_FLOAT_SPLIT*y.hi; hc = c-hc; tc = C-hc; hy = u-y.hi; U = C * y.hi; hy = u-hy; ty = y.hi-hy; // u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; u = hc*hy; u = u-U; t1 = hc*ty; u = u+t1; t1 = tc*hy; u = u+t1; t1 = tc*ty; u = u+t1; // c = ((((x.hi-U)-u)+x.lo)-C*y.lo)/y.hi; c = x.hi-U; c = c-u; c = c+x.lo; t1 = C*y.lo; c = c - t1; c = c/y.hi; hy = C+c; ty = C-hy; ty = ty+c; x.hi = hy; x.lo = ty;END_FIX return x;}quad_float sqrt(const quad_float& y) { if (y.hi < 0.0) Error("Quad: attempto to take square root of negative number"); if (y.hi == 0.0) return quad_float(0.0,0.0); double c; c = sqrt(y.hi); ForceToMem(&c); // This is fairly paranoid, but it doesn't cost too much.START_FIX DOUBLE p,q,hx,tx,u,uu,cc; DOUBLE t1; p = NTL_QUAD_FLOAT_SPLIT*c; hx = (c-p); hx = hx+p; tx = c-hx; p = hx*hx; q = hx*tx; q = q+q; u = p+q; uu = p-u; uu = uu+q; t1 = tx*tx; uu = uu+t1; cc = y.hi-u; cc = cc-uu; cc = cc+y.lo; t1 = c+c; cc = cc/t1; hx = c+cc; tx = c-hx; tx = tx+cc;END_FIX return quad_float(hx, tx);}void power(quad_float& z, const quad_float& a, long e){ quad_float res, u; unsigned long k; if (e < 0) k = -e; else k = e; res = 1.0; u = a; while (k) { if (k & 1) res = res * u; k = k >> 1; if (k) u = u * u; } if (e < 0) z = 1.0/res; else z = res;}void power2(quad_float& z, long e){ int ee; ee = e; if (ee != e) Error("overflow in power2"); z.hi = ldexp(1.0, ee); z.lo = 0;}long to_long(const quad_float& x){ DOUBLE fhi, flo; long lhi, llo; fhi = floor(x.hi); if (fhi > 0) lhi = -long(-fhi); else lhi = long(fhi); if (fhi == x.hi) { flo = floor(x.lo); llo = long(flo); } else llo = 0; return lhi + llo;}// This version of ZZ to quad_float coversion relies on the// precise rounding rules implemented by the ZZ to double conversion.void conv(quad_float& z, const ZZ& a){ DOUBLE xhi, xlo; conv(xhi, a); if (!IsFinite(&xhi)) { z.hi = xhi; z.lo = 0; return; } static ZZ t; conv(t, xhi); sub(t, a, t); conv(xlo, t); normalize(z, xhi, xlo); if (fabs(z.hi) < NTL_FDOUBLE_PRECISION && z.lo != 0) Error("internal error: ZZ to quad_float conversion");} void conv(ZZ& z, const quad_float& x){ static ZZ t1, t2, t3; DOUBLE fhi, flo; fhi = floor(x.hi); if (fhi == x.hi) { flo = floor(x.lo); conv(t1, fhi); conv(t2, flo); add(z, t1, t2); } else conv(z, fhi);}ostream& operator<<(ostream& s, const quad_float& a){ quad_float aa = a; if (!IsFinite(&aa)) { s << "NaN"; return s; } long old_p = RR::precision(); long old_op = RR::OutputPrecision(); RR::SetPrecision(long(3.33*quad_float::oprec) + 10); RR::SetOutputPrecision(quad_float::oprec); static RR t; conv(t, a); s << t; RR::SetPrecision(old_p); RR::SetOutputPrecision(old_op); return s;}istream& operator>>(istream& s, quad_float& x){ long old_p = RR::precision(); RR::SetPrecision(4*NTL_DOUBLE_PRECISION); static RR t; s >> t; conv(x, t); RR::SetPrecision(old_p); return s;}void random(quad_float& x){ long old_p = RR::precision(); RR::SetPrecision(4*NTL_DOUBLE_PRECISION); static RR t; random(t); conv(x, t); RR::SetPrecision(old_p);}quad_float random_quad_float(){ quad_float x; random(x); return x;} long IsFinite(quad_float *x){ return IsFinite(&x->hi) && IsFinite(&x->lo);}long PrecisionOK(){START_FIX long k; DOUBLE l1 = (double)1; DOUBLE lh = 1/(double)2; DOUBLE epsilon; DOUBLE fudge, oldfudge; epsilon = l1; fudge = l1+l1; k = 0; do { k++; epsilon = epsilon * lh; oldfudge = fudge; fudge = l1 + epsilon; } while (fudge > l1 && fudge < oldfudge);END_FIX return k == NTL_DOUBLE_PRECISION;}quad_float floor(const quad_float& x){ DOUBLE fhi, flo, u, v; fhi = floor(x.hi); if (fhi != x.hi) return quad_float(fhi, 0.0); else { flo = floor(x.lo);START_FIX u = fhi + flo; v = fhi - u; v = v + flo;END_FIX return quad_float(u, v); }}quad_float ceil(const quad_float& x) { return -floor(-x);}quad_float trunc(const quad_float& x) { if (x>=0.0) return floor(x); else return -floor(-x);}long compare(const quad_float& x, const quad_float& y){ if (x.hi > y.hi) return 1; else if (x.hi < y.hi) return -1; else if (x.lo > y.lo) return 1; else if (x.lo < y.lo) return -1; else return 0;}quad_float fabs(const quad_float& x) { if (x.hi>=0.0) return x; else return -x; }quad_float to_quad_float(const char *s){ quad_float x; long old_p = RR::precision(); RR::SetPrecision(4*NTL_DOUBLE_PRECISION); static RR t; conv(t, s); conv(x, t); RR::SetPrecision(old_p); return x;}quad_float ldexp(const quad_float& x, long exp) { // x*2^exp if (int(exp) != exp) Error("quad_float ldexp: overflow"); return quad_float(ldexp(x.hi,int(exp)),ldexp(x.lo,int(exp)));}quad_float exp(const quad_float& x) { // New version 97 Aug 05/*! Calculate a quadruple-precision exponential! Method:! x x.log2(e) nint[x.log2(e)] + frac[x.log2(e)]! e = 2 = 2!! iy fy! = 2 . 2! Then! fy y.loge(2)! 2 = e!! Now y.loge(2) will be less than 0.3466 in absolute value.! This is halved and a Pade aproximation is used to approximate e^x over! the region (-0.1733, +0.1733). This approximation is then squared.! WARNING: No overflow checks!*/ if (x.hi<DBL_MIN_10_EXP*2.302585092994045684017991) return to_quad_float(0.0); if (x.hi>DBL_MAX_10_EXP*2.302585092994045684017991) { Error("exp(quad_float): overflow"); } const quad_float Log2 = to_quad_float("0.6931471805599453094172321214581765680755"); quad_float y,temp,ysq,sum1,sum2; long iy; y=x/Log2; temp = floor(y+0.5); iy = to_long(temp); y=(y-temp)*Log2; y=ldexp(y,-1L); ysq=y*y; sum1=y*((((ysq+3960.0)*ysq+2162160.0)*ysq+302702400.0)*ysq+8821612800.0); sum2=(((90.0*ysq+110880.0)*ysq+30270240.0)*ysq+2075673600.0)*ysq+17643225600.0;/*! sum2 + sum1 2.sum1! Now approximation = ----------- = 1 + ----------- = 1 + 2.temp! sum2 - sum1 sum2 - sum1!! Then (1 + 2.temp)^2 = 4.temp.(1 + temp) + 1*/ temp=sum1/(sum2-sum1); y=temp*(temp+1); y=ldexp(y,2L); return ldexp(y+1,iy);}quad_float log(const quad_float& t) { // Newton method. See Bailey, MPFUN if (t.hi <= 0.0) { Error("log(quad_float): argument must be positive"); } double s1 = log(t.hi); ForceToMem(&s1); // Again, this is fairly paranoid. quad_float s; s = s1; quad_float e; e=exp(s); return s+(t-e)/e; // Newton step}long operator> (const quad_float& x, const quad_float& y) { return (x.hi> y.hi) || (x.hi==y.hi && x.lo> y.lo); }long operator>=(const quad_float& x, const quad_float& y) { return (x.hi>y.hi) || (x.hi==y.hi && x.lo>=y.lo); }long operator< (const quad_float& x, const quad_float& y) { return (x.hi< y.hi) || (x.hi==y.hi && x.lo< y.lo); }long operator<=(const quad_float& x, const quad_float& y) { return (x.hi<y.hi) || (x.hi==y.hi && x.lo<=y.lo); }long operator==(const quad_float& x, const quad_float& y) { return x.hi==y.hi && x.lo==y.lo; }long operator!=(const quad_float& x, const quad_float& y) { return x.hi!=y.hi || x.lo!=y.lo; }NTL_END_IMPL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -