📄 xdouble.cpp
字号:
#include <NTL/xdouble.h>
#include <NTL/RR.h>
#include <NTL/new.h>
NTL_START_IMPL
long xdouble::oprec = 10;
void xdouble::SetOutputPrecision(long p)
{
if (p < 1) p = 1;
if (p >= (1L << (NTL_BITS_PER_LONG-4)))
Error("xdouble: output precision too big");
oprec = p;
}
void xdouble::normalize()
{
if (x == 0)
e = 0;
else if (x > 0) {
while (x < NTL_XD_HBOUND_INV) { x *= NTL_XD_BOUND; e--; }
while (x > NTL_XD_HBOUND) { x *= NTL_XD_BOUND_INV; e++; }
}
else {
while (x > -NTL_XD_HBOUND_INV) { x *= NTL_XD_BOUND; e--; }
while (x < -NTL_XD_HBOUND) { x *= NTL_XD_BOUND_INV; e++; }
}
if (e >= (1L << (NTL_BITS_PER_LONG-4)))
Error("xdouble: overflow");
if (e <= -(1L << (NTL_BITS_PER_LONG-4)))
Error("xdouble: underflow");
}
xdouble to_xdouble(double a)
{
if (a == 0 || a == 1 || (a > 0 && a >= NTL_XD_HBOUND_INV && a <= NTL_XD_HBOUND)
|| (a < 0 && a <= -NTL_XD_HBOUND_INV && a >= -NTL_XD_HBOUND)) {
return xdouble(a, 0);
}
if (!IsFinite(&a))
Error("double to xdouble conversion: non finite value");
xdouble z = xdouble(a, 0);
z.normalize();
return z;
}
void conv(double& xx, const xdouble& a)
{
double x;
long e;
x = a.x;
e = a.e;
while (e > 0) { x *= NTL_XD_BOUND; e--; }
while (e < 0) { x *= NTL_XD_BOUND_INV; e++; }
xx = x;
}
xdouble operator+(const xdouble& a, const xdouble& b)
{
xdouble z;
if (a.x == 0)
return b;
if (b.x == 0)
return a;
if (a.e == b.e) {
z.x = a.x + b.x;
z.e = a.e;
z.normalize();
return z;
}
else if (a.e > b.e) {
if (a.e > b.e+1)
return a;
z.x = a.x + b.x*NTL_XD_BOUND_INV;
z.e = a.e;
z.normalize();
return z;
}
else {
if (b.e > a.e+1)
return b;
z.x = a.x*NTL_XD_BOUND_INV + b.x;
z.e = b.e;
z.normalize();
return z;
}
}
xdouble operator-(const xdouble& a, const xdouble& b)
{
xdouble z;
if (a.x == 0)
return -b;
if (b.x == 0)
return a;
if (a.e == b.e) {
z.x = a.x - b.x;
z.e = a.e;
z.normalize();
return z;
}
else if (a.e > b.e) {
if (a.e > b.e+1)
return a;
z.x = a.x - b.x*NTL_XD_BOUND_INV;
z.e = a.e;
z.normalize();
return z;
}
else {
if (b.e > a.e+1)
return -b;
z.x = a.x*NTL_XD_BOUND_INV - b.x;
z.e = b.e;
z.normalize();
return z;
}
}
xdouble operator-(const xdouble& a)
{
xdouble z;
z.x = -a.x;
z.e = a.e;
return z;
}
xdouble operator*(const xdouble& a, const xdouble& b)
{
xdouble z;
z.e = a.e + b.e;
z.x = a.x * b.x;
z.normalize();
return z;
}
xdouble operator/(const xdouble& a, const xdouble& b)
{
xdouble z;
if (b.x == 0) Error("xdouble division by 0");
z.e = a.e - b.e;
z.x = a.x / b.x;
z.normalize();
return z;
}
long compare(const xdouble& a, const xdouble& b)
{
xdouble z = a - b;
if (z.x < 0)
return -1;
else if (z.x == 0)
return 0;
else
return 1;
}
long sign(const xdouble& z)
{
if (z.x < 0)
return -1;
else if (z.x == 0)
return 0;
else
return 1;
}
xdouble trunc(const xdouble& a)
{
if (a.x >= 0)
return floor(a);
else
return ceil(a);
}
xdouble floor(const xdouble& aa)
{
xdouble z;
xdouble a = aa;
ForceToMem(&a.x);
if (a.e == 0) {
z.x = floor(a.x);
z.e = 0;
z.normalize();
return z;
}
else if (a.e > 0) {
return a;
}
else {
if (a.x < 0)
return to_xdouble(-1);
else
return to_xdouble(0);
}
}
xdouble ceil(const xdouble& aa)
{
xdouble z;
xdouble a = aa;
ForceToMem(&a.x);
if (a.e == 0) {
z.x = ceil(a.x);
z.e = 0;
z.normalize();
return z;
}
else if (a.e > 0) {
return a;
}
else {
if (a.x < 0)
return to_xdouble(0);
else
return to_xdouble(1);
}
}
xdouble to_xdouble(const ZZ& a)
{
long old_p = RR::precision();
RR::SetPrecision(NTL_DOUBLE_PRECISION);
static RR t;
conv(t, a);
double x;
conv(x, t.mantissa());
xdouble y, z, res;
conv(y, x);
power2(z, t.exponent());
res = y*z;
RR::SetPrecision(old_p);
return res;
}
void conv(ZZ& x, const xdouble& a)
{
xdouble b = floor(a);
long old_p = RR::precision();
RR::SetPrecision(NTL_DOUBLE_PRECISION);
static RR t;
conv(t, b);
conv(x, t);
RR::SetPrecision(old_p);
}
xdouble fabs(const xdouble& a)
{
xdouble z;
z.e = a.e;
z.x = fabs(a.x);
return z;
}
xdouble sqrt(const xdouble& a)
{
if (a == 0)
return to_xdouble(0);
if (a < 0)
Error("xdouble: sqrt of negative number");
xdouble t;
if (a.e & 1) {
t.e = (a.e - 1)/2;
t.x = sqrt(a.x * NTL_XD_BOUND);
}
else {
t.e = a.e/2;
t.x = sqrt(a.x);
}
t.normalize();
return t;
}
void power(xdouble& z, const xdouble& a, const ZZ& e)
{
xdouble b, res;
b = a;
res = 1;
long n = NumBits(e);
long i;
for (i = n-1; i >= 0; i--) {
res = res * res;
if (bit(e, i))
res = res * b;
}
if (sign(e) < 0)
z = 1/res;
else
z = res;
}
void power(xdouble& z, const xdouble& a, long e)
{
static ZZ E;
E = e;
power(z, a, E);
}
void power2(xdouble& z, long e)
{
long hb = NTL_XD_HBOUND_LOG;
long b = 2*hb;
long q, r;
q = e/b;
r = e%b;
while (r >= hb) {
r -= b;
q++;
}
while (r < -hb) {
r += b;
q--;
}
if (q >= (1L << (NTL_BITS_PER_LONG-4)))
Error("xdouble: overflow");
if (q <= -(1L << (NTL_BITS_PER_LONG-4)))
Error("xdouble: underflow");
int rr = r;
double x = ldexp(1.0, rr);
z.x = x;
z.e = q;
}
void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c)
// z = a + b*c
{
double x;
long e;
e = b.e + c.e;
x = b.x * c.x;
if (x == 0) {
z = a;
return;
}
if (a.x == 0) {
z.e = e;
z.x = x;
z.normalize();
return;
}
if (a.e == e) {
z.x = a.x + x;
z.e = e;
z.normalize();
return;
}
else if (a.e > e) {
if (a.e > e+1) {
z = a;
return;
}
z.x = a.x + x*NTL_XD_BOUND_INV;
z.e = a.e;
z.normalize();
return;
}
else {
if (e > a.e+1) {
z.x = x;
z.e = e;
z.normalize();
return;
}
z.x = a.x*NTL_XD_BOUND_INV + x;
z.e = e;
z.normalize();
return;
}
}
void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c)
// z = a - b*c
{
double x;
long e;
e = b.e + c.e;
x = b.x * c.x;
if (x == 0) {
z = a;
return;
}
if (a.x == 0) {
z.e = e;
z.x = -x;
z.normalize();
return;
}
if (a.e == e) {
z.x = a.x - x;
z.e = e;
z.normalize();
return;
}
else if (a.e > e) {
if (a.e > e+1) {
z = a;
return;
}
z.x = a.x - x*NTL_XD_BOUND_INV;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -