📄 rr.cpp
字号:
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 + -