123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613 |
- /*
- * 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 */
|