LightDoubleDouble.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #ifndef MANDEL_LIGHTDOUBLEDOUBLE_H
  2. #define MANDEL_LIGHTDOUBLEDOUBLE_H
  3. #include <utility>
  4. namespace mnd
  5. {
  6. struct LightDoubleDouble;
  7. namespace ldd
  8. {
  9. using DoublePair = std::pair<double, double>;
  10. inline static DoublePair quickTwoSum(double a, double b)
  11. {
  12. double s = a + b;
  13. double e = b - (s - a);
  14. return { s, e };
  15. }
  16. inline DoublePair twoSum(double a, double b)
  17. {
  18. double s = a + b;
  19. double v = s - a;
  20. double e = (a - (s - v)) + (b - v);
  21. return { s, e };
  22. }
  23. inline DoublePair split(double a)
  24. {
  25. static const double splitter = double((1ULL << 27) + 1);
  26. double t = splitter * a;
  27. double ahi = t - (t - a);
  28. double alo = a - ahi;
  29. return { ahi, alo };
  30. }
  31. inline DoublePair twoProd(double a, double b)
  32. {
  33. double p = a * b;
  34. auto [ahi, alo] = split(a);
  35. auto [bhi, blo] = split(b);
  36. double e = ((ahi * bhi - p) + ahi * blo + alo * bhi) + alo * blo;
  37. return { p, e };
  38. }
  39. inline DoublePair twoProdFma(double a, double b)
  40. {
  41. double p = a * b;
  42. double e = std::fma(a, b, -p);
  43. return { p, e };
  44. }
  45. }
  46. }
  47. struct mnd::LightDoubleDouble
  48. {
  49. double x[2];
  50. inline LightDoubleDouble(double val) :
  51. x{ val, 0 }
  52. {}
  53. inline LightDoubleDouble(double u, double l) :
  54. x{ u, l }
  55. {}
  56. inline LightDoubleDouble(mnd::ldd::DoublePair dp) :
  57. x{ dp.first, dp.second }
  58. {}
  59. double operator[] (int i) const { return x[i]; }
  60. const double& operator[] (int i) { return x[i]; }
  61. private:
  62. };
  63. inline mnd::LightDoubleDouble operator+(const mnd::LightDoubleDouble& a,
  64. const mnd::LightDoubleDouble& b)
  65. {
  66. auto[s, e] = mnd::ldd::twoSum(a[0], b[0]);
  67. e += a[1] + b[1];
  68. return mnd::ldd::quickTwoSum(s, e);
  69. }
  70. inline mnd::LightDoubleDouble operator-(const mnd::LightDoubleDouble& a,
  71. const mnd::LightDoubleDouble& b)
  72. {
  73. auto[s, e] = mnd::ldd::twoSum(a[0], -b[0]);
  74. e += a[1] - b[1];
  75. return mnd::ldd::quickTwoSum(s, e);
  76. }
  77. inline mnd::LightDoubleDouble operator*(const mnd::LightDoubleDouble& a,
  78. const mnd::LightDoubleDouble& b)
  79. {
  80. auto[p1, p2] = mnd::ldd::twoProd(a[0], b[0]);
  81. p2 += a[0] * b[1] + a[1] * b[0];
  82. return mnd::ldd::quickTwoSum(p1, p2);
  83. }
  84. #endif // MANDEL_LIGHTDOUBLEDOUBLE_H