// Excerpts from: // inline.h // Excerpted and modified by Steve Vavasis, 2/00 for use in QMG 2.0. // doubledouble package is originally written by Keith Briggs. // These excerpts are covered by the // QMG license, with permission from Keith Briggs. // The entire doubledouble package is available on line at // http://www-epidem.plantsci.cam.ac.uk/~kbriggs/doubledouble.html // and is covered by the Gnu Public License. // KMB 98 Jan 19 // Keith Briggs. Last revised 98 Feb 09 /* Copyright (C) 1997 Keith Martin Briggs Except where otherwise indicated, this program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // 97 Aug 04 KMB added ldexp // 97 Jul 11 Moved this stuff out of quad.h, created inline.h so it can // be #included even if we're not inlining, by just "#define inline" // 97 Jul 12 Added all combos of doubledouble/double/int +-*/. Only a couple actually // written; most just call the others by swapping arguments. Generates // equivalent code with a good inlining compiler (tested with g++ 2.7.2). // - e.g., all subtraction is now done by addition of unary minus. // - removed if's from doubledouble*int. Zero-branch code is 2.5 faster (tested) // - generally cleaned up and re-organized the order of the functions, // now they're grouped nicely by function. // - tested Newton's division. Works but is terribly slow, because // it needs to do several doubledouble + and * operations, and doubledouble / // without it is about the same speed at doubledouble * anyway, so no win. // - moved recip here as an inline. // - checked and tested doubledouble/double (BUG?), seems fine. // Absolute value inline doubledouble fabs(const doubledouble& x) { if (x.h()>=0.0) return x; else return -x; } // Addition /* (C) W. Kahan 1989. Notice: This file may be distributed according to the license for QMG. The following additional terms apply to this routine. 1. This notice and copyright notices must remain attached to the programs and their translations. 2. Any use of this routine in a research or development project on the topic of computer arithmetic obliges the user to report his/her experience to W. Kahan. Other questions concerning QMG should be directed to S. Vavasis. 3. Neither the author nor the institution that employs him will be held responsible for the consequences of using a program for which neither has received payments. */ /////////////////////////////////////////////////////////////// /////////////////// Addition and Subtraction ///////////////// /////////////////////////////////////////////////////////////// // Binary addition inline doubledouble operator +(const doubledouble& x, const doubledouble& y) { double H, h, T, t, S, s, e, f; S = x.hi+y.hi; T = x.lo+y.lo; e = S-x.hi; f = T-x.lo; s = S-e; t = T-f; s = (y.hi-e)+(x.hi-s); t = (y.lo-f)+(x.lo-t); e = s+T; H = S+e; h = e+(S-H); e = t+h; doubledouble z; z.hi = H+e; z.lo = e+double(H-z.hi); return z; } inline doubledouble operator +(const double& x, const doubledouble& y) { double H, h, S, s, e; S = x+y.hi; e = S-x; s = S-e; s = (y.hi-e)+(x-s); H = S+(s+y.lo); h = (s+y.lo)+(S-H); doubledouble z; z.hi = H+h; z.lo = h+double(H-z.hi); return z; } inline doubledouble operator +(const doubledouble& x,const double& y ) { return y+x; } inline doubledouble operator +(const int x, const doubledouble& y) { return double(x)+y; } inline doubledouble operator +(const doubledouble& x, const int y) { return y+x; } // Subtraction inline doubledouble operator -(const doubledouble& x, const doubledouble& y) { return x+(-y); } inline doubledouble operator -(const double& x, const doubledouble& y) { return x+(-y); } inline doubledouble operator -(const int x, const doubledouble& y) { return x+(-y); } inline doubledouble operator -(const doubledouble& x, const double& y) { return x+(-y); } inline doubledouble operator -(const doubledouble& x, const int y) { return x+(-y); } ////////////////////////// Self-Addition /////////////////////// inline doubledouble& doubledouble::operator +=(const doubledouble& y) { double H, h, T, t, S, s, e, f; S = hi+y.hi; T = lo+y.lo; e = S-hi; f = T-lo; s = S-e; t = T-f; s = (y.hi-e)+(hi-s); t = (y.lo-f)+(lo-t); f = s+T; H = S+f; h = f+(S-H); hi = H+(t+h); lo = (t+h)+double(H-hi); return *this; } inline doubledouble& doubledouble::operator +=(const double& y) { double H, h, S, s, e, f; S = hi+y; e = S-hi; s = S-e; s = (y-e)+(hi-s); f = s+lo; H = S+f; h = f+(S-H); hi = H+h; lo = h+double(H-hi); return *this; } inline doubledouble& doubledouble::operator +=(const int y) { return *this += double(y); } // Self-Subtraction inline doubledouble& doubledouble::operator -=(const doubledouble& y) { return *this += -y; } inline doubledouble& doubledouble::operator -=(const double& y) { return *this += -y; } inline doubledouble& doubledouble::operator -=(const int y) { return *this += -y; } ///////////////////////////////////////////////////////////// //////////////////// Multiplication /////////////////////// ///////////////////////////////////////////////////////////// // Binary Multiplication inline doubledouble operator *(const doubledouble& x, const doubledouble& y) { double hx, tx, hy, ty, C, c; C = doubledouble::Split*x.hi; hx = C-x.hi; c = doubledouble::Split*y.hi; hx = C-hx; tx = x.hi-hx; hy = c-y.hi; C = x.hi*y.hi; hy = c-hy; ty = y.hi-hy; c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(x.hi*y.lo+x.lo*y.hi); doubledouble z; z.hi = C+c; hx=C-z.hi; z.lo = c+hx; return z; } // double*doubledouble inline doubledouble operator *(const double& x, const doubledouble& y) { double hx, tx, hy, ty, C, c; C = doubledouble::Split*x; hx = C-x; c = doubledouble::Split*y.hi; hx = C-hx ; tx = x-hx; hy = c-y.hi; C = x*y.hi; hy = c-hy; ty = y.hi - hy; c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+x*y.lo; doubledouble z; z.hi = C+c; z.lo = c+double(C-z.hi); return z; } inline doubledouble operator *(const int x, const doubledouble& y ) { return double(x)*y; } inline doubledouble operator *(const doubledouble& x, const double& y ) { return y*x; } inline doubledouble operator *(const doubledouble& x, const int y ) { return y*x; } // Self-multiplication inline doubledouble& doubledouble::operator *=(const doubledouble& y ) { double hx, tx, hy, ty, C, c; C = Split*hi; hx = C-hi; c = Split*y.hi; hx = C-hx; tx = hi-hx; hy = c-y.hi; C = hi*y.hi; hy = c-hy; ty = y.hi-hy; c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(hi*y.lo+lo*y.hi); hx = C+c; hi = hx; lo = c+double(C-hx); return *this; } inline doubledouble& doubledouble::operator *=(const double& y ) { double hx, tx, hy, ty, C, c; C = Split*hi; hx = C-hi; c = Split*y; hx = C-hx; tx = hi-hx; hy = c-y; C = hi*y; hy = c-hy; ty = y-hy; c = ((((hx*hy-C)+hx*ty)+tx*hy)+tx*ty)+(lo*y); hx = C+c; hi = hx; lo = c+double(C-hx); return *this; } inline doubledouble& doubledouble::operator *=(const int y ) { return *this *= double(y); } //////////////////////////////////////////////////////////////// ////////////////////////// Division ////////////////////////// //////////////////////////////////////////////////////////////// // Reciprocal inline doubledouble recip(const doubledouble& y) { double hc, tc, hy, ty, C, c, U, u; C = 1.0/y.h(); c = doubledouble::Split*C; hc =c-C; u = doubledouble::Split*y.h(); hc = c-hc; tc = C-hc; hy = u-y.h(); U = C*y.h(); hy = u-hy; ty = y.h()-hy; u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; c = ((((1.0-U)-u))-C*y.l())/y.h(); doubledouble z; z.hi = C+c; z.lo = double(C-z.hi)+c; return z; } inline doubledouble operator /(const doubledouble& x,const doubledouble& y ) { double hc, tc, hy, ty, C, c, U, u; C = x.hi/y.hi; c = doubledouble::Split*C; hc =c-C; u = doubledouble::Split*y.hi; hc = c-hc; tc = C-hc; hy = u-y.hi; U = C * y.hi; hy = u-hy; ty = y.hi-hy; u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; c = ((((x.hi-U)-u)+x.lo)-C*y.lo)/y.hi; doubledouble z; z.hi = C+c; z.lo = double(C-z.hi)+c; return z; } // double/doubledouble: inline doubledouble operator /(const double& x,const doubledouble& y ) { double hc, tc, hy, ty, C, c, U, u; C = x/y.hi; c = doubledouble::Split*C; hc =c-C; u = doubledouble::Split*y.hi; hc = c-hc; tc = C-hc; hy = u-y.hi; U = C*y.hi; hy = u-hy; ty = y.hi-hy; u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; c = ((((x-U)-u))-C*y.lo)/y.hi; doubledouble z; z.hi = C+c; z.lo = double(C-z.hi)+c; return z; } inline doubledouble operator /(const doubledouble& x,const double& y ) { double hc, tc, hy, ty, C, c, U, u; C = x.hi/y; c = doubledouble::Split*C; hc = c-C; u = doubledouble::Split*y; hc = c-hc; tc = C-hc; hy = u-y; U = C*y; hy = u-hy; ty = y-hy; u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; c = (((x.hi-U)-u)+x.lo)/y; doubledouble z; z.hi = C+c; z.lo = double(C-z.hi)+c; return z; } // doubledouble/int inline doubledouble operator /(const doubledouble& x, const int y) { return x/double(y); } inline doubledouble operator /(const int x, const doubledouble& y) { return double(x)/y; } // Self-division. inline doubledouble& doubledouble::operator /=(const doubledouble& y) { double hc, tc, hy, ty, C, c, U, u; C = hi/y.hi; c = Split*C; hc =c-C; u = Split*y.hi; hc = c-hc; tc = C-hc; hy = u-y.hi; U = C * y.hi; hy = u-hy; ty = y.hi-hy; u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; c = ((((hi-U)-u)+lo)-C*y.lo)/y.hi; u = C+c; hi = u; lo = double(C-u)+c; return *this; } inline doubledouble& doubledouble::operator /=(const double& y) { double hc, tc, hy, ty, C, c, U, u; C = hi/y; c = Split*C; hc =c-C; u = Split*y; hc = c-hc; tc = C-hc; hy = u-y; U = C * y; hy = u-hy; ty = y-hy; u = (((hc*hy-U)+hc*ty)+tc*hy)+tc*ty; c = (((hi-U)-u)+lo)/y; u = C+c; hi = u; lo = double(C-u)+c; return *this; } inline doubledouble& doubledouble::operator /=(const int y) { return *this/=double(y); }