⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rr.c

📁 数值算法库for Unix
💻 C
📖 第 1 页 / 共 2 页
字号:
   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 + -