You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

613 lines
14 KiB

/*
* include/dd_inline.h
*
* This work was supported by the Director, Office of Science, Division
* of Mathematical, Information, and Computational Sciences of the
* U.S. Department of Energy under contract number DE-AC03-76SF00098.
*
* Copyright (c) 2000-2001
*
* Contains small functions (suitable for inlining) in the double-double
* arithmetic package.
*/
#ifndef _QD_DD_INLINE_H
#define _QD_DD_INLINE_H
#include <cmath>
#include <qd/inline.h>
#ifndef QD_INLINE
#define inline
#endif
/*********** Additions ************/
/* double-double = double + double */
inline dd_real dd_real::add(double a, double b) {
double s, e;
s = qd::two_sum(a, b, e);
return dd_real(s, e);
}
/* double-double + double */
inline dd_real operator+(const dd_real &a, double b) {
double s1, s2;
s1 = qd::two_sum(a.x[0], b, s2);
s2 += a.x[1];
s1 = qd::quick_two_sum(s1, s2, s2);
return dd_real(s1, s2);
}
/* double-double + double-double */
inline dd_real dd_real::ieee_add(const dd_real &a, const dd_real &b) {
/* This one satisfies IEEE style error bound,
due to K. Briggs and W. Kahan. */
double s1, s2, t1, t2;
s1 = qd::two_sum(a.x[0], b.x[0], s2);
t1 = qd::two_sum(a.x[1], b.x[1], t2);
s2 += t1;
s1 = qd::quick_two_sum(s1, s2, s2);
s2 += t2;
s1 = qd::quick_two_sum(s1, s2, s2);
return dd_real(s1, s2);
}
inline dd_real dd_real::sloppy_add(const dd_real &a, const dd_real &b) {
/* This is the less accurate version ... obeys Cray-style
error bound. */
double s, e;
s = qd::two_sum(a.x[0], b.x[0], e);
e += (a.x[1] + b.x[1]);
s = qd::quick_two_sum(s, e, e);
return dd_real(s, e);
}
inline dd_real operator+(const dd_real &a, const dd_real &b) {
#ifndef QD_IEEE_ADD
return dd_real::sloppy_add(a, b);
#else
return dd_real::ieee_add(a, b);
#endif
}
/* double + double-double */
inline dd_real operator+(double a, const dd_real &b) {
return (b + a);
}
/*********** Self-Additions ************/
/* double-double += double */
inline dd_real &dd_real::operator+=(double a) {
double s1, s2;
s1 = qd::two_sum(x[0], a, s2);
s2 += x[1];
x[0] = qd::quick_two_sum(s1, s2, x[1]);
return *this;
}
/* double-double += double-double */
inline dd_real &dd_real::operator+=(const dd_real &a) {
#ifndef QD_IEEE_ADD
double s, e;
s = qd::two_sum(x[0], a.x[0], e);
e += x[1];
e += a.x[1];
x[0] = qd::quick_two_sum(s, e, x[1]);
return *this;
#else
double s1, s2, t1, t2;
s1 = qd::two_sum(x[0], a.x[0], s2);
t1 = qd::two_sum(x[1], a.x[1], t2);
s2 += t1;
s1 = qd::quick_two_sum(s1, s2, s2);
s2 += t2;
x[0] = qd::quick_two_sum(s1, s2, x[1]);
return *this;
#endif
}
/*********** Subtractions ************/
/* double-double = double - double */
inline dd_real dd_real::sub(double a, double b) {
double s, e;
s = qd::two_diff(a, b, e);
return dd_real(s, e);
}
/* double-double - double */
inline dd_real operator-(const dd_real &a, double b) {
double s1, s2;
s1 = qd::two_diff(a.x[0], b, s2);
s2 += a.x[1];
s1 = qd::quick_two_sum(s1, s2, s2);
return dd_real(s1, s2);
}
/* double-double - double-double */
inline dd_real operator-(const dd_real &a, const dd_real &b) {
#ifndef QD_IEEE_ADD
double s, e;
s = qd::two_diff(a.x[0], b.x[0], e);
e += a.x[1];
e -= b.x[1];
s = qd::quick_two_sum(s, e, e);
return dd_real(s, e);
#else
double s1, s2, t1, t2;
s1 = qd::two_diff(a.x[0], b.x[0], s2);
t1 = qd::two_diff(a.x[1], b.x[1], t2);
s2 += t1;
s1 = qd::quick_two_sum(s1, s2, s2);
s2 += t2;
s1 = qd::quick_two_sum(s1, s2, s2);
return dd_real(s1, s2);
#endif
}
/* double - double-double */
inline dd_real operator-(double a, const dd_real &b) {
double s1, s2;
s1 = qd::two_diff(a, b.x[0], s2);
s2 -= b.x[1];
s1 = qd::quick_two_sum(s1, s2, s2);
return dd_real(s1, s2);
}
/*********** Self-Subtractions ************/
/* double-double -= double */
inline dd_real &dd_real::operator-=(double a) {
double s1, s2;
s1 = qd::two_diff(x[0], a, s2);
s2 += x[1];
x[0] = qd::quick_two_sum(s1, s2, x[1]);
return *this;
}
/* double-double -= double-double */
inline dd_real &dd_real::operator-=(const dd_real &a) {
#ifndef QD_IEEE_ADD
double s, e;
s = qd::two_diff(x[0], a.x[0], e);
e += x[1];
e -= a.x[1];
x[0] = qd::quick_two_sum(s, e, x[1]);
return *this;
#else
double s1, s2, t1, t2;
s1 = qd::two_diff(x[0], a.x[0], s2);
t1 = qd::two_diff(x[1], a.x[1], t2);
s2 += t1;
s1 = qd::quick_two_sum(s1, s2, s2);
s2 += t2;
x[0] = qd::quick_two_sum(s1, s2, x[1]);
return *this;
#endif
}
/*********** Unary Minus ***********/
inline dd_real dd_real::operator-() const {
return dd_real(-x[0], -x[1]);
}
/*********** Multiplications ************/
/* double-double = double * double */
inline dd_real dd_real::mul(double a, double b) {
double p, e;
p = qd::two_prod(a, b, e);
return dd_real(p, e);
}
/* double-double * (2.0 ^ exp) */
inline dd_real ldexp(const dd_real &a, int exp) {
return dd_real(std::ldexp(a.x[0], exp), std::ldexp(a.x[1], exp));
}
/* double-double * double, where double is a power of 2. */
inline dd_real mul_pwr2(const dd_real &a, double b) {
return dd_real(a.x[0] * b, a.x[1] * b);
}
/* double-double * double */
inline dd_real operator*(const dd_real &a, double b) {
double p1, p2;
p1 = qd::two_prod(a.x[0], b, p2);
p2 += (a.x[1] * b);
p1 = qd::quick_two_sum(p1, p2, p2);
return dd_real(p1, p2);
}
/* double-double * double-double */
inline dd_real operator*(const dd_real &a, const dd_real &b) {
double p1, p2;
p1 = qd::two_prod(a.x[0], b.x[0], p2);
p2 += (a.x[0] * b.x[1] + a.x[1] * b.x[0]);
p1 = qd::quick_two_sum(p1, p2, p2);
return dd_real(p1, p2);
}
/* double * double-double */
inline dd_real operator*(double a, const dd_real &b) {
return (b * a);
}
/*********** Self-Multiplications ************/
/* double-double *= double */
inline dd_real &dd_real::operator*=(double a) {
double p1, p2;
p1 = qd::two_prod(x[0], a, p2);
p2 += x[1] * a;
x[0] = qd::quick_two_sum(p1, p2, x[1]);
return *this;
}
/* double-double *= double-double */
inline dd_real &dd_real::operator*=(const dd_real &a) {
double p1, p2;
p1 = qd::two_prod(x[0], a.x[0], p2);
p2 += a.x[1] * x[0];
p2 += a.x[0] * x[1];
x[0] = qd::quick_two_sum(p1, p2, x[1]);
return *this;
}
/*********** Divisions ************/
inline dd_real dd_real::div(double a, double b) {
double q1, q2;
double p1, p2;
double s, e;
q1 = a / b;
/* Compute a - q1 * b */
p1 = qd::two_prod(q1, b, p2);
s = qd::two_diff(a, p1, e);
e -= p2;
/* get next approximation */
q2 = (s + e) / b;
s = qd::quick_two_sum(q1, q2, e);
return dd_real(s, e);
}
/* double-double / double */
inline dd_real operator/(const dd_real &a, double b) {
double q1, q2;
double p1, p2;
double s, e;
dd_real r;
q1 = a.x[0] / b; /* approximate quotient. */
/* Compute this - q1 * d */
p1 = qd::two_prod(q1, b, p2);
s = qd::two_diff(a.x[0], p1, e);
e += a.x[1];
e -= p2;
/* get next approximation. */
q2 = (s + e) / b;
/* renormalize */
r.x[0] = qd::quick_two_sum(q1, q2, r.x[1]);
return r;
}
inline dd_real dd_real::sloppy_div(const dd_real &a, const dd_real &b) {
double s1, s2;
double q1, q2;
dd_real r;
q1 = a.x[0] / b.x[0]; /* approximate quotient */
/* compute this - q1 * dd */
r = b * q1;
s1 = qd::two_diff(a.x[0], r.x[0], s2);
s2 -= r.x[1];
s2 += a.x[1];
/* get next approximation */
q2 = (s1 + s2) / b.x[0];
/* renormalize */
r.x[0] = qd::quick_two_sum(q1, q2, r.x[1]);
return r;
}
inline dd_real dd_real::accurate_div(const dd_real &a, const dd_real &b) {
double q1, q2, q3;
dd_real r;
q1 = a.x[0] / b.x[0]; /* approximate quotient */
r = a - q1 * b;
q2 = r.x[0] / b.x[0];
r -= (q2 * b);
q3 = r.x[0] / b.x[0];
q1 = qd::quick_two_sum(q1, q2, q2);
r = dd_real(q1, q2) + q3;
return r;
}
/* double-double / double-double */
inline dd_real operator/(const dd_real &a, const dd_real &b) {
#ifdef QD_SLOPPY_DIV
return dd_real::sloppy_div(a, b);
#else
return dd_real::accurate_div(a, b);
#endif
}
/* double / double-double */
inline dd_real operator/(double a, const dd_real &b) {
return dd_real(a) / b;
}
inline dd_real inv(const dd_real &a) {
return 1.0 / a;
}
/*********** Self-Divisions ************/
/* double-double /= double */
inline dd_real &dd_real::operator/=(double a) {
*this = *this / a;
return *this;
}
/* double-double /= double-double */
inline dd_real &dd_real::operator/=(const dd_real &a) {
*this = *this / a;
return *this;
}
/********** Remainder **********/
inline dd_real drem(const dd_real &a, const dd_real &b) {
dd_real n = nint(a / b);
return (a - n * b);
}
inline dd_real divrem(const dd_real &a, const dd_real &b, dd_real &r) {
dd_real n = nint(a / b);
r = a - n * b;
return n;
}
/*********** Squaring **********/
inline dd_real sqr(const dd_real &a) {
double p1, p2;
double s1, s2;
p1 = qd::two_sqr(a.x[0], p2);
p2 += 2.0 * a.x[0] * a.x[1];
p2 += a.x[1] * a.x[1];
s1 = qd::quick_two_sum(p1, p2, s2);
return dd_real(s1, s2);
}
inline dd_real dd_real::sqr(double a) {
double p1, p2;
p1 = qd::two_sqr(a, p2);
return dd_real(p1, p2);
}
/********** Exponentiation **********/
inline dd_real dd_real::operator^(int n) {
return npwr(*this, n);
}
/*********** Assignments ************/
/* double-double = double */
inline dd_real &dd_real::operator=(double a) {
x[0] = a;
x[1] = 0.0;
return *this;
}
/*********** Equality Comparisons ************/
/* double-double == double */
inline bool operator==(const dd_real &a, double b) {
return (a.x[0] == b && a.x[1] == 0.0);
}
/* double-double == double-double */
inline bool operator==(const dd_real &a, const dd_real &b) {
return (a.x[0] == b.x[0] && a.x[1] == b.x[1]);
}
/* double == double-double */
inline bool operator==(double a, const dd_real &b) {
return (a == b.x[0] && b.x[1] == 0.0);
}
/*********** Greater-Than Comparisons ************/
/* double-double > double */
inline bool operator>(const dd_real &a, double b) {
return (a.x[0] > b || (a.x[0] == b && a.x[1] > 0.0));
}
/* double-double > double-double */
inline bool operator>(const dd_real &a, const dd_real &b) {
return (a.x[0] > b.x[0] || (a.x[0] == b.x[0] && a.x[1] > b.x[1]));
}
/* double > double-double */
inline bool operator>(double a, const dd_real &b) {
return (a > b.x[0] || (a == b.x[0] && b.x[1] < 0.0));
}
/*********** Less-Than Comparisons ************/
/* double-double < double */
inline bool operator<(const dd_real &a, double b) {
return (a.x[0] < b || (a.x[0] == b && a.x[1] < 0.0));
}
/* double-double < double-double */
inline bool operator<(const dd_real &a, const dd_real &b) {
return (a.x[0] < b.x[0] || (a.x[0] == b.x[0] && a.x[1] < b.x[1]));
}
/* double < double-double */
inline bool operator<(double a, const dd_real &b) {
return (a < b.x[0] || (a == b.x[0] && b.x[1] > 0.0));
}
/*********** Greater-Than-Or-Equal-To Comparisons ************/
/* double-double >= double */
inline bool operator>=(const dd_real &a, double b) {
return (a.x[0] > b || (a.x[0] == b && a.x[1] >= 0.0));
}
/* double-double >= double-double */
inline bool operator>=(const dd_real &a, const dd_real &b) {
return (a.x[0] > b.x[0] || (a.x[0] == b.x[0] && a.x[1] >= b.x[1]));
}
/* double >= double-double */
inline bool operator>=(double a, const dd_real &b) {
return (b <= a);
}
/*********** Less-Than-Or-Equal-To Comparisons ************/
/* double-double <= double */
inline bool operator<=(const dd_real &a, double b) {
return (a.x[0] < b || (a.x[0] == b && a.x[1] <= 0.0));
}
/* double-double <= double-double */
inline bool operator<=(const dd_real &a, const dd_real &b) {
return (a.x[0] < b.x[0] || (a.x[0] == b.x[0] && a.x[1] <= b.x[1]));
}
/* double <= double-double */
inline bool operator<=(double a, const dd_real &b) {
return (b >= a);
}
/*********** Not-Equal-To Comparisons ************/
/* double-double != double */
inline bool operator!=(const dd_real &a, double b) {
return (a.x[0] != b || a.x[1] != 0.0);
}
/* double-double != double-double */
inline bool operator!=(const dd_real &a, const dd_real &b) {
return (a.x[0] != b.x[0] || a.x[1] != b.x[1]);
}
/* double != double-double */
inline bool operator!=(double a, const dd_real &b) {
return (a != b.x[0] || b.x[1] != 0.0);
}
/*********** Micellaneous ************/
/* this == 0 */
inline bool dd_real::is_zero() const {
return (x[0] == 0.0);
}
/* this == 1 */
inline bool dd_real::is_one() const {
return (x[0] == 1.0 && x[1] == 0.0);
}
/* this > 0 */
inline bool dd_real::is_positive() const {
return (x[0] > 0.0);
}
/* this < 0 */
inline bool dd_real::is_negative() const {
return (x[0] < 0.0);
}
/* Absolute value */
inline dd_real abs(const dd_real &a) {
return (a.x[0] < 0.0) ? -a : a;
}
inline dd_real fabs(const dd_real &a) {
return abs(a);
}
/* Round to Nearest integer */
inline dd_real nint(const dd_real &a) {
double hi = qd::nint(a.x[0]);
double lo;
if (hi == a.x[0]) {
/* High word is an integer already. Round the low word.*/
lo = qd::nint(a.x[1]);
/* Renormalize. This is needed if x[0] = some integer, x[1] = 1/2.*/
hi = qd::quick_two_sum(hi, lo, lo);
} else {
/* High word is not an integer. */
lo = 0.0;
if (std::abs(hi-a.x[0]) == 0.5 && a.x[1] < 0.0) {
/* There is a tie in the high word, consult the low word
to break the tie. */
hi -= 1.0; /* NOTE: This does not cause INEXACT. */
}
}
return dd_real(hi, lo);
}
inline dd_real floor(const dd_real &a) {
double hi = std::floor(a.x[0]);
double lo = 0.0;
if (hi == a.x[0]) {
/* High word is integer already. Round the low word. */
lo = std::floor(a.x[1]);
hi = qd::quick_two_sum(hi, lo, lo);
}
return dd_real(hi, lo);
}
inline dd_real ceil(const dd_real &a) {
double hi = std::ceil(a.x[0]);
double lo = 0.0;
if (hi == a.x[0]) {
/* High word is integer already. Round the low word. */
lo = std::ceil(a.x[1]);
hi = qd::quick_two_sum(hi, lo, lo);
}
return dd_real(hi, lo);
}
inline dd_real aint(const dd_real &a) {
return (a.x[0] >= 0.0) ? floor(a) : ceil(a);
}
/* Cast to double. */
inline double to_double(const dd_real &a) {
return a.x[0];
}
/* Cast to int. */
inline int to_int(const dd_real &a) {
return static_cast<int>(a.x[0]);
}
/* Random number generator */
inline dd_real dd_real::rand() {
return ddrand();
}
#endif /* _QD_DD_INLINE_H */