📄 rr.c
字号:
old_p = RR::prec; RR::prec = NTL_DOUBLE_PRECISION; conv(a_hi, a); // high order bits sub(a_lo, a, a_hi); // low order bits z = to_quad_float(a_hi.x)*power2_quad_float(a_hi.e) + to_quad_float(a_lo.x)*power2_quad_float(a_lo.e); RR::prec = old_p;}void conv(RR& x, const char *s){ long c; long sign; ZZ a, b; long i = 0; if (!s) Error("bad RR input"); c = s[i]; while (c == ' ' || c == '\n' || c == '\t') { i++; c = s[i]; } if (c == '-') { sign = -1; i++; c = s[i]; } else sign = 1; long got1 = 0; long got_dot = 0; long got2 = 0; a = 0; b = 1; if (c >= '0' && c <= '9') { got1 = 1; while (c >= '0' && c <= '9') { mul(a, a, 10); add(a, a, c-'0'); i++; c = s[i]; } } if (c == '.') { got_dot = 1; i++; c = s[i]; if (c >= '0' && c <= '9') { got2 = 1; while (c >= '0' && c <= '9') { mul(a, a, 10); add(a, a, c-'0'); mul(b, b, 10); i++; c = s[i]; } } } if (got_dot && !got1 && !got2) Error("bad RR input"); ZZ e; long got_e = 0; long e_sign; if (c == 'e' || c == 'E') { got_e = 1; i++; c = s[i]; if (c == '-') { e_sign = -1; i++; c = s[i]; } else if (c == '+') { e_sign = 1; i++; c = s[i]; } else e_sign = 1; if (c < '0' || c > '9') Error("bad RR input"); e = 0; while (c >= '0' && c <= '9') { mul(e, e, 10); add(e, e, c-'0'); i++; c = s[i]; } } if (!got1 && !got2 && !got_e) Error("bad RR input"); RR t1, t2, v; long old_p = RR::precision(); if (got1 || got2) { RR::SetPrecision(max(NumBits(a), NumBits(b))); conv(t1, a); conv(t2, b); if (got_e) RR::SetPrecision(old_p + 10); else RR::prec = old_p; div(v, t1, t2); } else set(v); if (sign < 0) negate(v, v); if (got_e) { if (e >= (1L << (NTL_BITS_PER_LONG-4))) Error("RR input overflow"); long E; conv(E, e); if (e_sign < 0) E = -E; RR::SetPrecision(old_p + 10); power(t1, to_RR(10), E); mul(v, v, t1); RR::prec = old_p; } xcopy(x, v);}void ReallyComputeE(RR& res){ long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR s, s1, t; s = 1; t = 1; long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); div(t, t, i); } RR::SetPrecision(p); xcopy(res, s);}void ComputeE(RR& res){ static long prec = 0; static RR e; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputeE(e); RR::SetPrecision(p); } xcopy(res, e);}void exp(RR& res, const RR& x){ if (x >= (1L << (NTL_BITS_PER_LONG-4)) || x <= -(1L << (NTL_BITS_PER_LONG-4))) Error("RR: overflow"); long p = RR::precision(); // step 0: write x = n + f, n an integer and |f| <= 1/2 // careful -- we want to compute f to > p bits of precision RR f, nn; RR::SetPrecision(NTL_BITS_PER_LONG); round(nn, x); RR::SetPrecision(p + 10); sub(f, x, nn); long n = to_long(nn); // step 1: calculate t1 = e^n by repeated squaring RR::SetPrecision(p + NumBits(n) + 10); RR e; ComputeE(e); RR::SetPrecision(p + 10); RR t1; power(t1, e, n); // step 2: calculate t2 = e^f using Taylor series expansion RR::SetPrecision(p + NumBits(p) + 10); RR t2, s, s1, t; long i; s = 0; t = 1; for (i = 1; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); div(t, t, i); } xcopy(t2, s); RR::SetPrecision(p); mul(res, t1, t2);}void ReallyComputeLn2(RR& res){ long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR s, s1, t, t1; s = 0; t = 0.5; t1 = 0.5; long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, 0.5); div(t, t1, i); } RR::SetPrecision(p); xcopy(res, s);}void ComputeLn2(RR& res){ static long prec = 0; static RR ln2; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputeLn2(ln2); RR::SetPrecision(p); } xcopy(res, ln2);}long Lg2(const RR& x){ return NumBits(x.mantissa()) + x.exponent();}void log(RR& res, const RR& x){ if (x <= 0) Error("argument to log must be positive"); long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR y; long n; // re-write x = 2^n * (1 - y), where -1/2 < y < 1/4 (so 3/4 < 1-y < 3/2) if (x > 0.75 && x < 1.5) { n = 0; sub(y, 1, x); } else { n = Lg2(x) - 1; RR t; power2(t, -n); mul(t, t, x); while (t > 1.5) { mul(t, t, 0.5); n++; } sub(y, 1, t); } // compute s = - ln(1-y) by power series expansion RR s, s1, t, t1; s = 0; xcopy(t, y); xcopy(t1, y); long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, y); div(t, t1, i); } if (n == 0) t = 0; else { ComputeLn2(t); mul(t, t, n); } RR::SetPrecision(p); sub(res, t, s);}void ComputeLn10(RR& res){ static long prec = 0; static RR ln10; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); log(ln10, to_RR(10)); RR::SetPrecision(p); } xcopy(res, ln10);}void log10(RR& res, const RR& x){ long p = RR::precision(); RR::SetPrecision(p + 10); RR ln10, t1, t2; ComputeLn10(ln10); log(t1, x); div(t2, t1, ln10); RR::SetPrecision(p); xcopy(res, t2);}void expm1(RR& res, const RR& x){ if (x < -0.5 || x > 0.5) { RR t; exp(t, x); sub(res, t, 1); return; } long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR f; xcopy(f, x); RR s, s1, t; long i; s = 0; xcopy(t, f); for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); div(t, t, i); } RR::SetPrecision(p); xcopy(res, s);}void log1p(RR& res, const RR& x){ if (x < -0.5 || x > 0.5) { log(res, 1 + x); return; } long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR y; negate(y, x); // compute s = - ln(1-y) by power series expansion RR s, s1, t, t1; s = 0; xcopy(t, y); xcopy(t1, y); long i; for (i = 2; ; i++) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, y); div(t, t1, i); } RR::SetPrecision(p); negate(res, s);}void pow(RR& res, const RR& x, const RR& y){ if (y == 0) { res = 1; return; } if (x == 0) { res = 0; return; } if (x == 1) { res = 1; return; } if (x < 0) { Error("pow: sorry...first argument to pow must be nonnegative"); } long p = RR::precision(); // calculate working precison...one could use p + NTL_BITS_PER_LONG + 10, // for example, but we want the behaviour to be machine independent. // so we calculate instead a rough approximation to log |y log(x)| RR t1, t2; long k; if (x > 0.5 && x < 1.5) { xcopy(t1, x - 1); k = Lg2(t1); } else { k = NumBits(Lg2(x)); } k += Lg2(y); if (k > NTL_BITS_PER_LONG+10) Error("RR: overflow"); if (k < 0) k = 0; RR::SetPrecision(p + k + 10); t1 = y*log(x); RR::SetPrecision(p); t2 = exp(t1); res = t2;}void ReallyComputePi(RR& res){ long p = RR::precision(); RR::SetPrecision(p + NumBits(p) + 10); RR sum1; RR s, s1, t, t1; s = 0; t = 0.5; t1 = 0.5; long i; for (i = 3; ; i+=2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, -0.25); div(t, t1, i); } xcopy(sum1, s); RR g; inv(g, to_RR(3)); // g = 1/3 s = 0; xcopy(t, g); xcopy(t1, g); sqr(g, g); negate(g, g); // g = -1/9 for (i = 3; ; i+=2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t1, t1, g); div(t, t1, i); } add(s, s, sum1); mul(s, s, 4); RR::SetPrecision(p); xcopy(res, s);}void ComputePi(RR& res){ static long prec = 0; static RR pi; long p = RR::precision(); if (prec <= p + 10) { prec = p + 20; RR::SetPrecision(prec); ReallyComputePi(pi); RR::SetPrecision(p); } xcopy(res, pi);}void sin(RR& res, const RR& x){ if (x == 0) { res = 0; return; } if (Lg2(x) > 1000) Error("sin: sorry...argument too large in absolute value"); long p = RR::precision(); RR pi, t1, f; RR n; // we want to make x^2 < 3, so that the series for sin(x) // converges nicely, without any nasty cancellations in the // first terms of the series. RR::SetPrecision(p + NumBits(p) + 10); if (x*x < 3) { xcopy(f, x); } else { // we want to write x/pi = n + f, |f| < 1/2.... // but we have to do *this* very carefully, so that f is computed // to precision > p. I know, this is sick! long p1; p1 = p + Lg2(x) + 20; for (;;) { RR::SetPrecision(p1); ComputePi(pi); xcopy(t1, x/pi); xcopy(n, floor(t1)); xcopy(f, t1 - n); if (f > 0.5) { n++; xcopy(f, t1 - n); } if (f == 0 || p1 < p - Lg2(f) + Lg2(n) + 10) { // we don't have enough bits of f...increase p1 and continue p1 = p1 + max(20, p1/10); } else break; } RR::SetPrecision(p + NumBits(p) + 10); ComputePi(pi); xcopy(f, pi * f); if (n != 0 && n.exponent() == 0) { // n is odd, so we negate f, which negates sin(f) xcopy(f, -f); } } // Boy, that was painful, but now its over, and we can simply apply // the series for sin(f) RR t2, s, s1, t; long i; s = 0; xcopy(t, f); for (i = 3; ; i=i+2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); mul(t, t, f); div(t, t, i-1); div(t, t, i); negate(t, t); } RR::SetPrecision(p); xcopy(res, s);}void cos(RR& res, const RR& x){ if (x == 0) { res = 1; return; } if (Lg2(x) > 1000) Error("cos: sorry...argument too large in absolute value"); long p = RR::precision(); RR pi, t1, f; RR n; // we want to write x/pi = (n+1/2) + f, |f| < 1/2.... // but we have to do *this* very carefully, so that f is computed // to precision > p. I know, this is sick! long p1; p1 = p + Lg2(x) + 20; for (;;) { RR::SetPrecision(p1); ComputePi(pi); xcopy(t1, x/pi); xcopy(n, floor(t1)); xcopy(f, t1 - (n + 0.5)); if (f == 0 || p1 < p - Lg2(f) + Lg2(n) + 10) { // we don't have enough bits of f...increase p1 and continue p1 = p1 + max(20, p1/10); } else break; } RR::SetPrecision(p + NumBits(p) + 10); ComputePi(pi); xcopy(f, pi * f); if (n == 0 || n.exponent() != 0) { // n is even, so we negate f, which negates sin(f) xcopy(f, -f); } // Boy, that was painful, but now its over, and we can simply apply // the series for sin(f) RR t2, s, s1, t; long i; s = 0; xcopy(t, f); for (i = 3; ; i=i+2) { add(s1, s, t); if (s == s1) break; xcopy(s, s1); mul(t, t, f); mul(t, t, f); div(t, t, i-1); div(t, t, i); negate(t, t); } RR::SetPrecision(p); xcopy(res, s);}ostream& operator<<(ostream& s, const RR& a){ if (IsZero(a)) { s << "0"; return s; } long old_p = RR::precision(); // we compute new_p and log_10_a precisely using sufficient // precision---this is necessary to achieve accuracy and // platform independent behaviour long temp_p = max(NumBits(RR::OutputPrecision()), NumBits(Lg2(a))) + 10; RR::SetPrecision(temp_p); RR ln2, ln10, log_2_10; ComputeLn2(ln2); ComputeLn10(ln10); log_2_10 = ln10/ln2; long new_p = to_long(RR::OutputPrecision()*log_2_10) + 20; long log_10_a = to_long(Lg2(a)/log_2_10); RR::SetPrecision(new_p); RR b; long neg; if (a < 0) { negate(b, a); neg = 1; } else { xcopy(b, a); neg = 0; } long k = RR::OutputPrecision() - log_10_a; RR c, d; power(c, to_RR(10), RR::OutputPrecision()); power(d, to_RR(10), log_10_a); div(b, b, d); mul(b, b, c); while (b < c) { mul(b, b, 10); k++; } while (b >= c) { div(b, b, 10); k--; } add(b, b, 0.5); k = -k; ZZ B; conv(B, b); long bp_len = RR::OutputPrecision()+10; char *bp = NTL_NEW_OP char[bp_len]; if (!bp) Error("RR output: out of memory"); long len, i; len = 0; do { if (len >= bp_len) Error("RR output: buffer overflow"); bp[len] = DivRem(B, B, 10) + '0'; len++; } while (B > 0); for (i = 0; i < len/2; i++) { char tmp; tmp = bp[i]; bp[i] = bp[len-1-i]; bp[len-1-i] = tmp; } i = len-1; while (bp[i] == '0') i--; k += (len-1-i); len = i+1; bp[len] = '\0'; if (k > 3 || k < -len - 3) { // use scientific notation if (neg) s << "-"; s << "0." << bp << "e" << (k + len); } else if (k >= 0) { if (neg) s << "-"; s << bp; for (i = 0; i < k; i++) s << "0"; } else if (k <= -len) { if (neg) s << "-"; s << "0."; for (i = 0; i < -len-k; i++) s << "0"; s << bp; } else { if (neg) s << "-"; for (i = 0; i < len+k; i++) s << bp[i]; s << "."; for (i = len+k; i < len; i++) s << bp[i]; } RR::SetPrecision(old_p); delete [] bp; return s;}NTL_END_IMPL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -