xdouble PowerOf10(const ZZ& e) { static NTL_CHEAP_THREAD_LOCAL long init = 0; static NTL_CHEAP_THREAD_LOCAL long k = 0; NTL_TLS_LOCAL(xdouble, v10k); if (!init) { k = ComputeMax10Power(); RRPush push; RR::SetPrecision(NTL_DOUBLE_PRECISION); v10k = to_xdouble(power(to_RR(10), k)); init = 1; } ZZ e1; long neg; if (e < 0) { e1 = -e; neg = 1; } else { e1 = e; neg = 0; } long r; ZZ q; r = DivRem(q, e1, k); RRPush push; RR::SetPrecision(NTL_DOUBLE_PRECISION); xdouble x1 = to_xdouble(power(to_RR(10), r)); xdouble x2 = power(v10k, q); xdouble x3 = x1*x2; if (neg) x3 = 1/x3; return x3; }
long ComputeMax10Power() { RRPush push; RR::SetPrecision(NTL_BITS_PER_LONG); RR ln2, ln10; ComputeLn2(ln2); ComputeLn10(ln10); long k = to_long( to_RR(NTL_OVFBND/2) * ln2 / ln10 ); return k; }
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 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); }
// ECM primitive void ECM(ZZ& q, const ZZ& n, const ZZ& _bnd, double failure_prob, bool verbose) { ZZ bnd; SqrRoot(bnd,n); if (_bnd>0 && _bnd<bnd) bnd=_bnd; long B1,B2,D; double prob; ECM_parameters(B1,B2,prob,D,NumBits(bnd),NumBits(n)); if (verbose) std::cout<<"ECM: bnd="<<NumBits(bnd)<<"bits B1="<<B1<<" B2="<<B2 <<" D="<<D<<" prob="<<prob<<std::endl; if (failure_prob<=0) { // run "forever" if (verbose) std::cout<<"ECM: expected ncurves="<<(1/prob)<<std::endl; ECM(q,n,NTL_MAX_LONG,B1,B2,D,verbose); } else if (failure_prob>=1) { // run on one curve ECM(q,n,1,B1,B2,D,verbose); } else { // run just the right number of times // failure_prob = (1-prob)^ncurves; double ncurves_d; if (prob<0.1) ncurves_d = to_double(log(failure_prob)/log1p(to_RR(-prob))); else ncurves_d = log(failure_prob)/log(1-prob); long ncurves = ncurves_d<=1 ? 1 : (ncurves_d>=NTL_MAX_LONG ? NTL_MAX_LONG : (long)ncurves_d); if (verbose) std::cout<<"ECM: good_prob="<<prob<<" failure_prob="<<failure_prob <<" ncurves="<<ncurves<<std::endl; ECM(q,n,ncurves,B1,B2,D,verbose); } }
ostream& operator<<(ostream& s, const xdouble& a) { if (a == 0) { s << "0"; return s; } RRPush push; long temp_p = long(log(fabs(log(fabs(a))) + 1.0)/log(2.0)) + 10; RR::SetPrecision(temp_p); RR ln2, ln10, log_2_10; ComputeLn2(ln2); ComputeLn10(ln10); log_2_10 = ln10/ln2; ZZ log_10_a = to_ZZ( (to_RR(a.e)*to_RR(2*NTL_XD_HBOUND_LOG) + log(fabs(a.x))/log(2.0))/log_2_10); xdouble b; long neg; if (a < 0) { b = -a; neg = 1; } else { b = a; neg = 0; } ZZ k = xdouble::OutputPrecision() - log_10_a; xdouble c, d; c = PowerOf10(to_ZZ(xdouble::OutputPrecision())); d = PowerOf10(log_10_a); b = b / d; b = b * c; while (b < c) { b = b * 10.0; k++; } while (b >= c) { b = b / 10.0; k--; } b = b + 0.5; k = -k; ZZ B; conv(B, b); long bp_len = xdouble::OutputPrecision()+10; UniqueArray<char> bp_store; bp_store.SetLength(bp_len); char *bp = bp_store.get(); long len, i; len = 0; do { if (len >= bp_len) LogicError("xdouble output: buffer overflow"); bp[len] = IntValToChar(DivRem(B, B, 10)); 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 { long kk = to_long(k); if (kk >= 0) { if (neg) s << "-"; s << bp; for (i = 0; i < kk; i++) s << "0"; } else if (kk <= -len) { if (neg) s << "-"; s << "0."; for (i = 0; i < -len-kk; i++) s << "0"; s << bp; } else { if (neg) s << "-"; for (i = 0; i < len+kk; i++) s << bp[i]; s << "."; for (i = len+kk; i < len; i++) s << bp[i]; } } return s; }
void inv(RR& z, const RR& a) { NTL_TLS_LOCAL_INIT(RR, one, (to_RR(1))); div(z, one, a); }
void conv(RR& x, const char *s) { long c; long cval; long sign; ZZ a, b; long i = 0; if (!s) Error("bad RR input"); c = s[i]; while (IsWhiteSpace(c)) { 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; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got1 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); i++; c = s[i]; cval = CharToIntVal(c); } } if (c == '.') { got_dot = 1; i++; c = s[i]; cval = CharToIntVal(c); if (cval >= 0 && cval <= 9) { got2 = 1; while (cval >= 0 && cval <= 9) { mul(a, a, 10); add(a, a, cval); mul(b, b, 10); i++; c = s[i]; cval = CharToIntVal(c); } } } 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; cval = CharToIntVal(c); if (cval < 0 || cval > 9) Error("bad RR input"); e = 0; while (cval >= 0 && cval <= 9) { mul(e, e, 10); add(e, e, cval); i++; c = s[i]; cval = CharToIntVal(c); } } if (!got1 && !got2 && !got_e) Error("bad RR input"); RR t1, t2, v; long old_p = RR::precision(); if (got1 || got2) { ConvPrec(t1, a, max(NumBits(a), 1)); ConvPrec(t2, b, NumBits(b)); if (got_e) RR::SetPrecision(old_p + 10); div(v, t1, t2); } else set(v); if (sign < 0) negate(v, v); if (got_e) { if (e >= NTL_OVFBND) 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 inv(RR& z, const RR& a) { static RR one = to_RR(1); div(z, one, a); }