Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:31:07

0001 /*
0002  * include/qd_inline.h
0003  *
0004  * This work was supported by the Director, Office of Science, Division
0005  * of Mathematical, Information, and Computational Sciences of the
0006  * U.S. Department of Energy under contract number DE-AC03-76SF00098.
0007  *
0008  * Copyright (c) 2000-2001
0009  *
0010  * Contains small functions (suitable for inlining) in the quad-double
0011  * arithmetic package.
0012  */
0013 #ifndef _QD_QD_INLINE_H
0014 #define _QD_QD_INLINE_H
0015 
0016 #include <cmath>
0017 #include <qd/inline.h>
0018 
0019 #ifndef QD_INLINE
0020 #define inline
0021 #endif
0022 
0023 /********** Constructors **********/
0024 inline qd_real::qd_real(double x0, double x1, double x2, double x3) {
0025   x[0] = x0;
0026   x[1] = x1;
0027   x[2] = x2;
0028   x[3] = x3;
0029 }
0030 
0031 inline qd_real::qd_real(const double *xx) {
0032   x[0] = xx[0];
0033   x[1] = xx[1];
0034   x[2] = xx[2];
0035   x[3] = xx[3];
0036 }
0037 
0038 inline qd_real::qd_real(double x0) {
0039   x[0] = x0;
0040   x[1] = x[2] = x[3] = 0.0;
0041 }
0042 
0043 inline qd_real::qd_real() {
0044     x[0] = 0.0; 
0045     x[1] = 0.0; 
0046     x[2] = 0.0; 
0047     x[3] = 0.0; 
0048 }
0049 
0050 inline qd_real::qd_real(const dd_real &a) {
0051   x[0] = a._hi();
0052   x[1] = a._lo();
0053   x[2] = x[3] = 0.0;
0054 }
0055 
0056 inline qd_real::qd_real(int i) {
0057   x[0] = static_cast<double>(i);
0058   x[1] = x[2] = x[3] = 0.0;
0059 }
0060 
0061 /********** Accessors **********/
0062 inline double qd_real::operator[](int i) const {
0063   return x[i];
0064 }
0065 
0066 inline double &qd_real::operator[](int i) {
0067   return x[i];
0068 }
0069 
0070 inline bool qd_real::isnan() const {
0071   return QD_ISNAN(x[0]) || QD_ISNAN(x[1]) || QD_ISNAN(x[2]) || QD_ISNAN(x[3]);
0072 }
0073 
0074 /********** Renormalization **********/
0075 namespace qd {
0076 inline void quick_renorm(double &c0, double &c1, 
0077                          double &c2, double &c3, double &c4) {
0078   double t0, t1, t2, t3;
0079   double s;
0080   s  = qd::quick_two_sum(c3, c4, t3);
0081   s  = qd::quick_two_sum(c2, s , t2);
0082   s  = qd::quick_two_sum(c1, s , t1);
0083   c0 = qd::quick_two_sum(c0, s , t0);
0084 
0085   s  = qd::quick_two_sum(t2, t3, t2);
0086   s  = qd::quick_two_sum(t1, s , t1);
0087   c1 = qd::quick_two_sum(t0, s , t0);
0088 
0089   s  = qd::quick_two_sum(t1, t2, t1);
0090   c2 = qd::quick_two_sum(t0, s , t0);
0091   
0092   c3 = t0 + t1;
0093 }
0094 
0095 inline void renorm(double &c0, double &c1, 
0096                    double &c2, double &c3) {
0097   double s0, s1, s2 = 0.0, s3 = 0.0;
0098 
0099   if (QD_ISINF(c0)) return;
0100 
0101   s0 = qd::quick_two_sum(c2, c3, c3);
0102   s0 = qd::quick_two_sum(c1, s0, c2);
0103   c0 = qd::quick_two_sum(c0, s0, c1);
0104 
0105   s0 = c0;
0106   s1 = c1;
0107   if (s1 != 0.0) {
0108     s1 = qd::quick_two_sum(s1, c2, s2);
0109     if (s2 != 0.0)
0110       s2 = qd::quick_two_sum(s2, c3, s3);
0111     else
0112       s1 = qd::quick_two_sum(s1, c3, s2);
0113   } else {
0114     s0 = qd::quick_two_sum(s0, c2, s1);
0115     if (s1 != 0.0)
0116       s1 = qd::quick_two_sum(s1, c3, s2);
0117     else
0118       s0 = qd::quick_two_sum(s0, c3, s1);
0119   }
0120 
0121   c0 = s0;
0122   c1 = s1;
0123   c2 = s2;
0124   c3 = s3;
0125 }
0126 
0127 inline void renorm(double &c0, double &c1, 
0128                    double &c2, double &c3, double &c4) {
0129   double s0, s1, s2 = 0.0, s3 = 0.0;
0130 
0131   if (QD_ISINF(c0)) return;
0132 
0133   s0 = qd::quick_two_sum(c3, c4, c4);
0134   s0 = qd::quick_two_sum(c2, s0, c3);
0135   s0 = qd::quick_two_sum(c1, s0, c2);
0136   c0 = qd::quick_two_sum(c0, s0, c1);
0137 
0138   s0 = c0;
0139   s1 = c1;
0140 
0141   if (s1 != 0.0) {
0142     s1 = qd::quick_two_sum(s1, c2, s2);
0143     if (s2 != 0.0) {
0144       s2 = qd::quick_two_sum(s2, c3, s3);
0145       if (s3 != 0.0)
0146         s3 += c4;
0147       else
0148         s2 = qd::quick_two_sum(s2, c4, s3);
0149     } else {
0150       s1 = qd::quick_two_sum(s1, c3, s2);
0151       if (s2 != 0.0)
0152         s2 = qd::quick_two_sum(s2, c4, s3);
0153       else
0154         s1 = qd::quick_two_sum(s1, c4, s2);
0155     }
0156   } else {
0157     s0 = qd::quick_two_sum(s0, c2, s1);
0158     if (s1 != 0.0) {
0159       s1 = qd::quick_two_sum(s1, c3, s2);
0160       if (s2 != 0.0)
0161         s2 = qd::quick_two_sum(s2, c4, s3);
0162       else
0163         s1 = qd::quick_two_sum(s1, c4, s2);
0164     } else {
0165       s0 = qd::quick_two_sum(s0, c3, s1);
0166       if (s1 != 0.0)
0167         s1 = qd::quick_two_sum(s1, c4, s2);
0168       else
0169         s0 = qd::quick_two_sum(s0, c4, s1);
0170     }
0171   }
0172 
0173   c0 = s0;
0174   c1 = s1;
0175   c2 = s2;
0176   c3 = s3;
0177 }
0178 }
0179 
0180 inline void qd_real::renorm() {
0181   qd::renorm(x[0], x[1], x[2], x[3]);
0182 }
0183 
0184 inline void qd_real::renorm(double &e) {
0185   qd::renorm(x[0], x[1], x[2], x[3], e);
0186 }
0187 
0188 
0189 /********** Additions ************/
0190 namespace qd {
0191 
0192 inline void three_sum(double &a, double &b, double &c) {
0193   double t1, t2, t3;
0194   t1 = qd::two_sum(a, b, t2);
0195   a  = qd::two_sum(c, t1, t3);
0196   b  = qd::two_sum(t2, t3, c);
0197 }
0198 
0199 inline void three_sum2(double &a, double &b, double &c) {
0200   double t1, t2, t3;
0201   t1 = qd::two_sum(a, b, t2);
0202   a  = qd::two_sum(c, t1, t3);
0203   b = t2 + t3;
0204 }
0205 
0206 }
0207 
0208 /* quad-double + double */
0209 inline qd_real operator+(const qd_real &a, double b) {
0210   double c0, c1, c2, c3;
0211   double e;
0212 
0213   c0 = qd::two_sum(a[0], b, e);
0214   c1 = qd::two_sum(a[1], e, e);
0215   c2 = qd::two_sum(a[2], e, e);
0216   c3 = qd::two_sum(a[3], e, e);
0217 
0218   qd::renorm(c0, c1, c2, c3, e);
0219 
0220   return qd_real(c0, c1, c2, c3);
0221 }
0222 
0223 /* quad-double + double-double */
0224 inline qd_real operator+(const qd_real &a, const dd_real &b) {
0225 
0226   double s0, s1, s2, s3;
0227   double t0, t1;
0228 
0229   s0 = qd::two_sum(a[0], b._hi(), t0);
0230   s1 = qd::two_sum(a[1], b._lo(), t1);
0231 
0232   s1 = qd::two_sum(s1, t0, t0);
0233 
0234   s2 = a[2];
0235   qd::three_sum(s2, t0, t1);
0236 
0237   s3 = qd::two_sum(t0, a[3], t0);
0238   t0 += t1;
0239 
0240   qd::renorm(s0, s1, s2, s3, t0);
0241   return qd_real(s0, s1, s2, s3);
0242 }
0243 
0244 
0245 /* double + quad-double */
0246 inline qd_real operator+(double a, const qd_real &b) {
0247   return (b + a);
0248 }
0249 
0250 /* double-double + quad-double */
0251 inline qd_real operator+(const dd_real &a, const qd_real &b) {
0252   return (b + a);
0253 }
0254 
0255 namespace qd {
0256 
0257 /* s = quick_three_accum(a, b, c) adds c to the dd-pair (a, b).
0258  * If the result does not fit in two doubles, then the sum is 
0259  * output into s and (a,b) contains the remainder.  Otherwise
0260  * s is zero and (a,b) contains the sum. */
0261 inline double quick_three_accum(double &a, double &b, double c) {
0262   double s;
0263   bool za, zb;
0264 
0265   s = qd::two_sum(b, c, b);
0266   s = qd::two_sum(a, s, a);
0267 
0268   za = (a != 0.0);
0269   zb = (b != 0.0);
0270 
0271   if (za && zb)
0272     return s;
0273 
0274   if (!zb) {
0275     b = a;
0276     a = s;
0277   } else {
0278     a = s;
0279   }
0280 
0281   return 0.0;
0282 }
0283 
0284 }
0285 
0286 inline qd_real qd_real::ieee_add(const qd_real &a, const qd_real &b) {
0287   int i, j, k;
0288   double s, t;
0289   double u, v;   /* double-length accumulator */
0290   double x[4] = {0.0, 0.0, 0.0, 0.0};
0291   
0292   i = j = k = 0;
0293   if (std::abs(a[i]) > std::abs(b[j]))
0294     u = a[i++];
0295   else
0296     u = b[j++];
0297   if (std::abs(a[i]) > std::abs(b[j]))
0298     v = a[i++];
0299   else
0300     v = b[j++];
0301 
0302   u = qd::quick_two_sum(u, v, v);
0303   
0304   while (k < 4) {
0305     if (i >= 4 && j >= 4) {
0306       x[k] = u;
0307       if (k < 3)
0308         x[++k] = v;
0309       break;
0310     }
0311 
0312     if (i >= 4)
0313       t = b[j++];
0314     else if (j >= 4)
0315       t = a[i++];
0316     else if (std::abs(a[i]) > std::abs(b[j])) {
0317       t = a[i++];
0318     } else
0319       t = b[j++];
0320 
0321     s = qd::quick_three_accum(u, v, t);
0322 
0323     if (s != 0.0) {
0324       x[k++] = s;
0325     }
0326   }
0327 
0328   /* add the rest. */
0329   for (k = i; k < 4; k++)
0330     x[3] += a[k];
0331   for (k = j; k < 4; k++)
0332     x[3] += b[k];
0333 
0334   qd::renorm(x[0], x[1], x[2], x[3]);
0335   return qd_real(x[0], x[1], x[2], x[3]);
0336 }
0337 
0338 inline qd_real qd_real::sloppy_add(const qd_real &a, const qd_real &b) {
0339   /*
0340   double s0, s1, s2, s3;
0341   double t0, t1, t2, t3;
0342   
0343   s0 = qd::two_sum(a[0], b[0], t0);
0344   s1 = qd::two_sum(a[1], b[1], t1);
0345   s2 = qd::two_sum(a[2], b[2], t2);
0346   s3 = qd::two_sum(a[3], b[3], t3);
0347 
0348   s1 = qd::two_sum(s1, t0, t0);
0349   qd::three_sum(s2, t0, t1);
0350   qd::three_sum2(s3, t0, t2);
0351   t0 = t0 + t1 + t3;
0352 
0353   qd::renorm(s0, s1, s2, s3, t0);
0354   return qd_real(s0, s1, s2, s3, t0);
0355   */
0356 
0357   /* Same as above, but addition re-organized to minimize
0358      data dependency ... unfortunately some compilers are
0359      not very smart to do this automatically */
0360   double s0, s1, s2, s3;
0361   double t0, t1, t2, t3;
0362 
0363   double v0, v1, v2, v3;
0364   double u0, u1, u2, u3;
0365   double w0, w1, w2, w3;
0366 
0367   s0 = a[0] + b[0];
0368   s1 = a[1] + b[1];
0369   s2 = a[2] + b[2];
0370   s3 = a[3] + b[3];
0371 
0372   v0 = s0 - a[0];
0373   v1 = s1 - a[1];
0374   v2 = s2 - a[2];
0375   v3 = s3 - a[3];
0376 
0377   u0 = s0 - v0;
0378   u1 = s1 - v1;
0379   u2 = s2 - v2;
0380   u3 = s3 - v3;
0381 
0382   w0 = a[0] - u0;
0383   w1 = a[1] - u1;
0384   w2 = a[2] - u2;
0385   w3 = a[3] - u3;
0386 
0387   u0 = b[0] - v0;
0388   u1 = b[1] - v1;
0389   u2 = b[2] - v2;
0390   u3 = b[3] - v3;
0391 
0392   t0 = w0 + u0;
0393   t1 = w1 + u1;
0394   t2 = w2 + u2;
0395   t3 = w3 + u3;
0396 
0397   s1 = qd::two_sum(s1, t0, t0);
0398   qd::three_sum(s2, t0, t1);
0399   qd::three_sum2(s3, t0, t2);
0400   t0 = t0 + t1 + t3;
0401 
0402   /* renormalize */
0403   qd::renorm(s0, s1, s2, s3, t0);
0404   return qd_real(s0, s1, s2, s3);
0405 }
0406 
0407 /* quad-double + quad-double */
0408 inline qd_real operator+(const qd_real &a, const qd_real &b) {
0409 #ifndef QD_IEEE_ADD
0410   return qd_real::sloppy_add(a, b);
0411 #else
0412   return qd_real::ieee_add(a, b);
0413 #endif
0414 }
0415 
0416 
0417 
0418 /********** Self-Additions ************/
0419 /* quad-double += double */
0420 inline qd_real &qd_real::operator+=(double a) {
0421   *this = *this + a;
0422   return *this;
0423 }
0424 
0425 /* quad-double += double-double */
0426 inline qd_real &qd_real::operator+=(const dd_real &a) {
0427   *this = *this + a;
0428   return *this;
0429 }
0430 
0431 /* quad-double += quad-double */
0432 inline qd_real &qd_real::operator+=(const qd_real &a) {
0433   *this = *this + a;
0434   return *this;
0435 }
0436 
0437 /********** Unary Minus **********/
0438 inline qd_real qd_real::operator-() const {
0439   return qd_real(-x[0], -x[1], -x[2], -x[3]);
0440 }
0441 
0442 /********** Subtractions **********/
0443 inline qd_real operator-(const qd_real &a, double b) {
0444   return (a + (-b));
0445 }
0446 
0447 inline qd_real operator-(double a, const qd_real &b) {
0448   return (a + (-b));
0449 }
0450 
0451 inline qd_real operator-(const qd_real &a, const dd_real &b) {
0452   return (a + (-b));
0453 }
0454 
0455 inline qd_real operator-(const dd_real &a, const qd_real &b) {
0456   return (a + (-b));
0457 }
0458 
0459 inline qd_real operator-(const qd_real &a, const qd_real &b) {
0460   return (a + (-b));
0461 }
0462 
0463 /********** Self-Subtractions **********/
0464 inline qd_real &qd_real::operator-=(double a) {
0465   return ((*this) += (-a));
0466 }
0467 
0468 inline qd_real &qd_real::operator-=(const dd_real &a) {
0469   return ((*this) += (-a));
0470 }
0471 
0472 inline qd_real &qd_real::operator-=(const qd_real &a) {
0473   return ((*this) += (-a));
0474 }
0475 
0476 
0477 inline qd_real operator*(double a, const qd_real &b) {
0478   return (b * a);
0479 }
0480 
0481 inline qd_real operator*(const dd_real &a, const qd_real &b) {
0482   return (b * a);
0483 }
0484 
0485 inline qd_real mul_pwr2(const qd_real &a, double b) {
0486   return qd_real(a[0] * b, a[1] * b, a[2] * b, a[3] * b);
0487 }
0488 
0489 /********** Multiplications **********/
0490 inline qd_real operator*(const qd_real &a, double b) {
0491   double p0, p1, p2, p3;
0492   double q0, q1, q2;
0493   double s0, s1, s2, s3, s4;
0494 
0495   p0 = qd::two_prod(a[0], b, q0);
0496   p1 = qd::two_prod(a[1], b, q1);
0497   p2 = qd::two_prod(a[2], b, q2);
0498   p3 = a[3] * b;
0499 
0500   s0 = p0;
0501 
0502   s1 = qd::two_sum(q0, p1, s2);
0503 
0504   qd::three_sum(s2, q1, p2);
0505 
0506   qd::three_sum2(q1, q2, p3);
0507   s3 = q1;
0508 
0509   s4 = q2 + p2;
0510 
0511   qd::renorm(s0, s1, s2, s3, s4);
0512   return qd_real(s0, s1, s2, s3);
0513 
0514 }
0515 
0516 /* quad-double * double-double */
0517 /* a0 * b0                        0
0518         a0 * b1                   1
0519         a1 * b0                   2
0520              a1 * b1              3
0521              a2 * b0              4
0522                   a2 * b1         5
0523                   a3 * b0         6
0524                        a3 * b1    7 */
0525 inline qd_real operator*(const qd_real &a, const dd_real &b) {
0526   double p0, p1, p2, p3, p4;
0527   double q0, q1, q2, q3, q4;
0528   double s0, s1, s2;
0529   double t0, t1;
0530 
0531   p0 = qd::two_prod(a[0], b._hi(), q0);
0532   p1 = qd::two_prod(a[0], b._lo(), q1);
0533   p2 = qd::two_prod(a[1], b._hi(), q2);
0534   p3 = qd::two_prod(a[1], b._lo(), q3);
0535   p4 = qd::two_prod(a[2], b._hi(), q4);
0536   
0537   qd::three_sum(p1, p2, q0);
0538   
0539   /* Five-Three-Sum */
0540   qd::three_sum(p2, p3, p4);
0541   q1 = qd::two_sum(q1, q2, q2);
0542   s0 = qd::two_sum(p2, q1, t0);
0543   s1 = qd::two_sum(p3, q2, t1);
0544   s1 = qd::two_sum(s1, t0, t0);
0545   s2 = t0 + t1 + p4;
0546   p2 = s0;
0547 
0548   p3 = a[2] * b._hi() + a[3] * b._lo() + q3 + q4;
0549   qd::three_sum2(p3, q0, s1);
0550   p4 = q0 + s2;
0551 
0552   qd::renorm(p0, p1, p2, p3, p4);
0553   return qd_real(p0, p1, p2, p3);
0554 }
0555 
0556 /* quad-double * quad-double */
0557 /* a0 * b0                    0
0558         a0 * b1               1
0559         a1 * b0               2
0560              a0 * b2          3
0561              a1 * b1          4
0562              a2 * b0          5
0563                   a0 * b3     6
0564                   a1 * b2     7
0565                   a2 * b1     8
0566                   a3 * b0     9  */
0567 inline qd_real qd_real::sloppy_mul(const qd_real &a, const qd_real &b) {
0568   double p0, p1, p2, p3, p4, p5;
0569   double q0, q1, q2, q3, q4, q5;
0570   double t0, t1;
0571   double s0, s1, s2;
0572 
0573   p0 = qd::two_prod(a[0], b[0], q0);
0574 
0575   p1 = qd::two_prod(a[0], b[1], q1);
0576   p2 = qd::two_prod(a[1], b[0], q2);
0577 
0578   p3 = qd::two_prod(a[0], b[2], q3);
0579   p4 = qd::two_prod(a[1], b[1], q4);
0580   p5 = qd::two_prod(a[2], b[0], q5);
0581 
0582   /* Start Accumulation */
0583   qd::three_sum(p1, p2, q0);
0584 
0585   /* Six-Three Sum  of p2, q1, q2, p3, p4, p5. */
0586   qd::three_sum(p2, q1, q2);
0587   qd::three_sum(p3, p4, p5);
0588   /* compute (s0, s1, s2) = (p2, q1, q2) + (p3, p4, p5). */
0589   s0 = qd::two_sum(p2, p3, t0);
0590   s1 = qd::two_sum(q1, p4, t1);
0591   s2 = q2 + p5;
0592   s1 = qd::two_sum(s1, t0, t0);
0593   s2 += (t0 + t1);
0594 
0595   /* O(eps^3) order terms */
0596   s1 += a[0]*b[3] + a[1]*b[2] + a[2]*b[1] + a[3]*b[0] + q0 + q3 + q4 + q5;
0597   qd::renorm(p0, p1, s0, s1, s2);
0598   return qd_real(p0, p1, s0, s1);
0599 }
0600 
0601 inline qd_real qd_real::accurate_mul(const qd_real &a, const qd_real &b) {
0602   double p0, p1, p2, p3, p4, p5;
0603   double q0, q1, q2, q3, q4, q5;
0604   double p6, p7, p8, p9;
0605   double q6, q7, q8, q9;
0606   double r0, r1;
0607   double t0, t1;
0608   double s0, s1, s2;
0609 
0610   p0 = qd::two_prod(a[0], b[0], q0);
0611 
0612   p1 = qd::two_prod(a[0], b[1], q1);
0613   p2 = qd::two_prod(a[1], b[0], q2);
0614 
0615   p3 = qd::two_prod(a[0], b[2], q3);
0616   p4 = qd::two_prod(a[1], b[1], q4);
0617   p5 = qd::two_prod(a[2], b[0], q5);
0618 
0619   /* Start Accumulation */
0620   qd::three_sum(p1, p2, q0);
0621 
0622   /* Six-Three Sum  of p2, q1, q2, p3, p4, p5. */
0623   qd::three_sum(p2, q1, q2);
0624   qd::three_sum(p3, p4, p5);
0625   /* compute (s0, s1, s2) = (p2, q1, q2) + (p3, p4, p5). */
0626   s0 = qd::two_sum(p2, p3, t0);
0627   s1 = qd::two_sum(q1, p4, t1);
0628   s2 = q2 + p5;
0629   s1 = qd::two_sum(s1, t0, t0);
0630   s2 += (t0 + t1);
0631 
0632   /* O(eps^3) order terms */
0633   p6 = qd::two_prod(a[0], b[3], q6);
0634   p7 = qd::two_prod(a[1], b[2], q7);
0635   p8 = qd::two_prod(a[2], b[1], q8);
0636   p9 = qd::two_prod(a[3], b[0], q9);
0637 
0638   /* Nine-Two-Sum of q0, s1, q3, q4, q5, p6, p7, p8, p9. */
0639   q0 = qd::two_sum(q0, q3, q3);
0640   q4 = qd::two_sum(q4, q5, q5);
0641   p6 = qd::two_sum(p6, p7, p7);
0642   p8 = qd::two_sum(p8, p9, p9);
0643   /* Compute (t0, t1) = (q0, q3) + (q4, q5). */
0644   t0 = qd::two_sum(q0, q4, t1);
0645   t1 += (q3 + q5);
0646   /* Compute (r0, r1) = (p6, p7) + (p8, p9). */
0647   r0 = qd::two_sum(p6, p8, r1);
0648   r1 += (p7 + p9);
0649   /* Compute (q3, q4) = (t0, t1) + (r0, r1). */
0650   q3 = qd::two_sum(t0, r0, q4);
0651   q4 += (t1 + r1);
0652   /* Compute (t0, t1) = (q3, q4) + s1. */
0653   t0 = qd::two_sum(q3, s1, t1);
0654   t1 += q4;
0655 
0656   /* O(eps^4) terms -- Nine-One-Sum */
0657   t1 += a[1] * b[3] + a[2] * b[2] + a[3] * b[1] + q6 + q7 + q8 + q9 + s2;
0658 
0659   qd::renorm(p0, p1, s0, t0, t1);
0660   return qd_real(p0, p1, s0, t0);
0661 }
0662 
0663 inline qd_real operator*(const qd_real &a, const qd_real &b) {
0664 #ifdef QD_SLOPPY_MUL
0665   return qd_real::sloppy_mul(a, b);
0666 #else
0667   return qd_real::accurate_mul(a, b);
0668 #endif
0669 }
0670 
0671 /* quad-double ^ 2  = (x0 + x1 + x2 + x3) ^ 2
0672                     = x0 ^ 2 + 2 x0 * x1 + (2 x0 * x2 + x1 ^ 2)
0673                                + (2 x0 * x3 + 2 x1 * x2)           */
0674 inline qd_real sqr(const qd_real &a) {
0675   double p0, p1, p2, p3, p4, p5;
0676   double q0, q1, q2, q3;
0677   double s0, s1;
0678   double t0, t1;
0679   
0680   p0 = qd::two_sqr(a[0], q0);
0681   p1 = qd::two_prod(2.0 * a[0], a[1], q1);
0682   p2 = qd::two_prod(2.0 * a[0], a[2], q2);
0683   p3 = qd::two_sqr(a[1], q3);
0684 
0685   p1 = qd::two_sum(q0, p1, q0);
0686 
0687   q0 = qd::two_sum(q0, q1, q1);
0688   p2 = qd::two_sum(p2, p3, p3);
0689 
0690   s0 = qd::two_sum(q0, p2, t0);
0691   s1 = qd::two_sum(q1, p3, t1);
0692 
0693   s1 = qd::two_sum(s1, t0, t0);
0694   t0 += t1;
0695 
0696   s1 = qd::quick_two_sum(s1, t0, t0);
0697   p2 = qd::quick_two_sum(s0, s1, t1);
0698   p3 = qd::quick_two_sum(t1, t0, q0);
0699 
0700   p4 = 2.0 * a[0] * a[3];
0701   p5 = 2.0 * a[1] * a[2];
0702 
0703   p4 = qd::two_sum(p4, p5, p5);
0704   q2 = qd::two_sum(q2, q3, q3);
0705 
0706   t0 = qd::two_sum(p4, q2, t1);
0707   t1 = t1 + p5 + q3;
0708 
0709   p3 = qd::two_sum(p3, t0, p4);
0710   p4 = p4 + q0 + t1;
0711 
0712   qd::renorm(p0, p1, p2, p3, p4);
0713   return qd_real(p0, p1, p2, p3);
0714 
0715 }
0716 
0717 /********** Self-Multiplication **********/
0718 /* quad-double *= double */
0719 inline qd_real &qd_real::operator*=(double a) {
0720   *this = (*this * a);
0721   return *this;
0722 }
0723 
0724 /* quad-double *= double-double */
0725 inline qd_real &qd_real::operator*=(const dd_real &a) {
0726   *this = (*this * a);
0727   return *this;
0728 }
0729 
0730 /* quad-double *= quad-double */
0731 inline qd_real &qd_real::operator*=(const qd_real &a) {
0732   *this = *this * a;
0733   return *this;
0734 }
0735 
0736 inline qd_real operator/ (const qd_real &a, const dd_real &b) {
0737 #ifdef QD_SLOPPY_DIV
0738   return qd_real::sloppy_div(a, b);
0739 #else
0740   return qd_real::accurate_div(a, b);
0741 #endif
0742 }
0743 
0744 inline qd_real operator/(const qd_real &a, const qd_real &b) {
0745 #ifdef QD_SLOPPY_DIV
0746   return qd_real::sloppy_div(a, b);
0747 #else
0748   return qd_real::accurate_div(a, b);
0749 #endif
0750 }
0751 
0752 /* double / quad-double */
0753 inline qd_real operator/(double a, const qd_real &b) {
0754   return qd_real(a) / b;
0755 }
0756 
0757 /* double-double / quad-double */
0758 inline qd_real operator/(const dd_real &a, const qd_real &b) {
0759   return qd_real(a) / b;
0760 }
0761 
0762 /********** Self-Divisions **********/
0763 /* quad-double /= double */
0764 inline qd_real &qd_real::operator/=(double a) {
0765   *this = (*this / a);
0766   return *this;
0767 }
0768 
0769 /* quad-double /= double-double */
0770 inline qd_real &qd_real::operator/=(const dd_real &a) {
0771   *this = (*this / a);
0772   return *this;
0773 }
0774 
0775 /* quad-double /= quad-double */
0776 inline qd_real &qd_real::operator/=(const qd_real &a) {
0777   *this = (*this / a);
0778   return *this;
0779 }
0780 
0781 
0782 /********** Exponentiation **********/
0783 inline qd_real qd_real::operator^(int n) const {
0784   return pow(*this, n);
0785 }
0786 
0787 /********** Miscellaneous **********/
0788 inline qd_real abs(const qd_real &a) {
0789   return (a[0] < 0.0) ? -a : a;
0790 }
0791 
0792 inline qd_real fabs(const qd_real &a) {
0793   return abs(a);
0794 }
0795 
0796 /* Quick version.  May be off by one when qd is very close
0797    to the middle of two integers.                         */
0798 inline qd_real quick_nint(const qd_real &a) {
0799   qd_real r = qd_real(qd::nint(a[0]), qd::nint(a[1]), 
0800       qd::nint(a[2]), qd::nint(a[3]));
0801   r.renorm();
0802   return r;
0803 }
0804 
0805 /*********** Assignments ************/
0806 /* quad-double = double */
0807 inline qd_real &qd_real::operator=(double a) {
0808   x[0] = a;
0809   x[1] = x[2] = x[3] = 0.0;
0810   return *this;
0811 }
0812 
0813 /* quad-double = double-double */
0814 inline qd_real &qd_real::operator=(const dd_real &a) {
0815   x[0] = a._hi();
0816   x[1] = a._lo();
0817   x[2] = x[3] = 0.0;
0818   return *this;
0819 }
0820 
0821 /********** Equality Comparison **********/
0822 inline bool operator==(const qd_real &a, double b) {
0823   return (a[0] == b && a[1] == 0.0 && a[2] == 0.0 && a[3] == 0.0);
0824 }
0825 
0826 inline bool operator==(double a, const qd_real &b) {
0827   return (b == a);
0828 }
0829 
0830 inline bool operator==(const qd_real &a, const dd_real &b) {
0831   return (a[0] == b._hi() && a[1] == b._lo() && 
0832           a[2] == 0.0 && a[3] == 0.0);
0833 }
0834 
0835 inline bool operator==(const dd_real &a, const qd_real &b) {
0836   return (b == a);
0837 }
0838 
0839 inline bool operator==(const qd_real &a, const qd_real &b) {
0840   return (a[0] == b[0] && a[1] == b[1] && 
0841           a[2] == b[2] && a[3] == b[3]);
0842 }
0843 
0844 
0845 /********** Less-Than Comparison ***********/
0846 inline bool operator<(const qd_real &a, double b) {
0847   return (a[0] < b || (a[0] == b && a[1] < 0.0));
0848 }
0849 
0850 inline bool operator<(double a, const qd_real &b) {
0851   return (b > a);
0852 }
0853 
0854 inline bool operator<(const qd_real &a, const dd_real &b) {
0855   return (a[0] < b._hi() || 
0856           (a[0] == b._hi() && (a[1] < b._lo() ||
0857                             (a[1] == b._lo() && a[2] < 0.0))));
0858 }
0859 
0860 inline bool operator<(const dd_real &a, const qd_real &b) {
0861   return (b > a);
0862 }
0863 
0864 inline bool operator<(const qd_real &a, const qd_real &b) {
0865   return (a[0] < b[0] ||
0866           (a[0] == b[0] && (a[1] < b[1] ||
0867                             (a[1] == b[1] && (a[2] < b[2] ||
0868                                               (a[2] == b[2] && a[3] < b[3]))))));
0869 }
0870 
0871 /********** Greater-Than Comparison ***********/
0872 inline bool operator>(const qd_real &a, double b) {
0873   return (a[0] > b || (a[0] == b && a[1] > 0.0));
0874 }
0875 
0876 inline bool operator>(double a, const qd_real &b) {
0877   return (b < a);
0878 }
0879 
0880 inline bool operator>(const qd_real &a, const dd_real &b) {
0881   return (a[0] > b._hi() || 
0882           (a[0] == b._hi() && (a[1] > b._lo() ||
0883                             (a[1] == b._lo() && a[2] > 0.0))));
0884 }
0885 
0886 inline bool operator>(const dd_real &a, const qd_real &b) {
0887   return (b < a);
0888 }
0889 
0890 inline bool operator>(const qd_real &a, const qd_real &b) {
0891   return (a[0] > b[0] ||
0892           (a[0] == b[0] && (a[1] > b[1] ||
0893                             (a[1] == b[1] && (a[2] > b[2] ||
0894                                               (a[2] == b[2] && a[3] > b[3]))))));
0895 }
0896 
0897 
0898 /********** Less-Than-Or-Equal-To Comparison **********/
0899 inline bool operator<=(const qd_real &a, double b) {
0900   return (a[0] < b || (a[0] == b && a[1] <= 0.0));
0901 }
0902 
0903 inline bool operator<=(double a, const qd_real &b) {
0904   return (b >= a);
0905 }
0906 
0907 inline bool operator<=(const qd_real &a, const dd_real &b) {
0908   return (a[0] < b._hi() || 
0909           (a[0] == b._hi() && (a[1] < b._lo() || 
0910                             (a[1] == b._lo() && a[2] <= 0.0))));
0911 }
0912 
0913 inline bool operator<=(const dd_real &a, const qd_real &b) {
0914   return (b >= a);
0915 }
0916 
0917 inline bool operator<=(const qd_real &a, const qd_real &b) {
0918   return (a[0] < b[0] || 
0919           (a[0] == b[0] && (a[1] < b[1] ||
0920                             (a[1] == b[1] && (a[2] < b[2] ||
0921                                               (a[2] == b[2] && a[3] <= b[3]))))));
0922 }
0923 
0924 /********** Greater-Than-Or-Equal-To Comparison **********/
0925 inline bool operator>=(const qd_real &a, double b) {
0926   return (a[0] > b || (a[0] == b && a[1] >= 0.0));
0927 }
0928 
0929 inline bool operator>=(double a, const qd_real &b) {
0930   return (b <= a);
0931 }
0932 
0933 inline bool operator>=(const qd_real &a, const dd_real &b) {
0934   return (a[0] > b._hi() || 
0935           (a[0] == b._hi() && (a[1] > b._lo() || 
0936                             (a[1] == b._lo() && a[2] >= 0.0))));
0937 }
0938 
0939 inline bool operator>=(const dd_real &a, const qd_real &b) {
0940   return (b <= a);
0941 }
0942 
0943 inline bool operator>=(const qd_real &a, const qd_real &b) {
0944   return (a[0] > b[0] || 
0945           (a[0] == b[0] && (a[1] > b[1] ||
0946                             (a[1] == b[1] && (a[2] > b[2] ||
0947                                               (a[2] == b[2] && a[3] >= b[3]))))));
0948 }
0949 
0950 
0951 
0952 /********** Not-Equal-To Comparison **********/
0953 inline bool operator!=(const qd_real &a, double b) {
0954   return !(a == b);
0955 }
0956 
0957 inline bool operator!=(double a, const qd_real &b) {
0958   return !(a == b);
0959 }
0960 
0961 inline bool operator!=(const qd_real &a, const dd_real &b) {
0962   return !(a == b);
0963 }
0964 
0965 inline bool operator!=(const dd_real &a, const qd_real &b) {
0966   return !(a == b);
0967 }
0968 
0969 inline bool operator!=(const qd_real &a, const qd_real &b) {
0970   return !(a == b);
0971 }
0972 
0973 
0974 
0975 inline qd_real aint(const qd_real &a) {
0976   return (a[0] >= 0) ? floor(a) : ceil(a);
0977 }
0978 
0979 inline bool qd_real::is_zero() const {
0980   return (x[0] == 0.0);
0981 }
0982 
0983 inline bool qd_real::is_one() const {
0984   return (x[0] == 1.0 && x[1] == 0.0 && x[2] == 0.0 && x[3] == 0.0);
0985 }
0986 
0987 inline bool qd_real::is_positive() const {
0988   return (x[0] > 0.0);
0989 }
0990 
0991 inline bool qd_real::is_negative() const {
0992   return (x[0] < 0.0);
0993 }
0994 
0995 inline dd_real to_dd_real(const qd_real &a) {
0996   return dd_real(a[0], a[1]);
0997 }
0998 
0999 inline double to_double(const qd_real &a) {
1000   return a[0];
1001 }
1002 
1003 inline int to_int(const qd_real &a) {
1004   return static_cast<int>(a[0]);
1005 }
1006 
1007 inline qd_real inv(const qd_real &qd) {
1008   return 1.0 / qd;
1009 }
1010 
1011 inline qd_real max(const qd_real &a, const qd_real &b) {
1012   return (a > b) ? a : b;
1013 }
1014 
1015 inline qd_real max(const qd_real &a, const qd_real &b, 
1016                    const qd_real &c) {
1017   return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);
1018 }
1019 
1020 inline qd_real min(const qd_real &a, const qd_real &b) {
1021   return (a < b) ? a : b;
1022 }
1023 
1024 inline qd_real min(const qd_real &a, const qd_real &b, 
1025                    const qd_real &c) {
1026   return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c);
1027 }
1028 
1029 /* Random number generator */
1030 inline qd_real qd_real::rand() {
1031   return qdrand();
1032 }
1033 
1034 inline qd_real ldexp(const qd_real &a, int n) {
1035   return qd_real(std::ldexp(a[0], n), std::ldexp(a[1], n), 
1036                  std::ldexp(a[2], n), std::ldexp(a[3], n));
1037 }
1038 
1039 #endif /* _QD_QD_INLINE_H */