LightDoubleDouble.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #ifndef MANDEL_LIGHTDOUBLEDOUBLE_H
  2. #define MANDEL_LIGHTDOUBLEDOUBLE_H
  3. #include <utility>
  4. namespace mnd
  5. {
  6. struct LightDoubleDouble;
  7. struct LightDoubleFloat;
  8. namespace ldd
  9. {
  10. template<typename T>
  11. using Pair = std::pair<T, T>;
  12. using DoublePair = Pair<double>;
  13. using FloatPair = Pair<float>;
  14. template<typename T>
  15. inline static Pair<T> quickTwoSum(T a, T b)
  16. {
  17. T s = a + b;
  18. T e = b - (s - a);
  19. return { s, e };
  20. }
  21. template<typename T>
  22. inline Pair<T> twoSum(T a, T b)
  23. {
  24. T s = a + b;
  25. T v = s - a;
  26. T e = (a - (s - v)) + (b - v);
  27. return { s, e };
  28. }
  29. inline Pair<double> split(double a)
  30. {
  31. static const double splitter = double((1ULL << 27) + 1);
  32. double t = splitter * a;
  33. double ahi = t - (t - a);
  34. double alo = a - ahi;
  35. return { ahi, alo };
  36. }
  37. template<typename T>
  38. inline Pair<T> twoProd(T a, T b)
  39. {
  40. T p = a * b;
  41. auto [ahi, alo] = split(a);
  42. auto [bhi, blo] = split(b);
  43. T e = ((ahi * bhi - p) + ahi * blo + alo * bhi) + alo * blo;
  44. return { p, e };
  45. }
  46. template<typename T>
  47. inline Pair<T> twoProdFma(T a, T b)
  48. {
  49. T p = a * b;
  50. T e = std::fma(a, b, -p);
  51. return { p, e };
  52. }
  53. }
  54. }
  55. struct mnd::LightDoubleDouble
  56. {
  57. double x[2];
  58. inline LightDoubleDouble(double val) :
  59. x{ val, 0 }
  60. {}
  61. inline LightDoubleDouble(double u, double l) :
  62. x{ u, l }
  63. {}
  64. inline LightDoubleDouble(mnd::ldd::DoublePair dp) :
  65. x{ dp.first, dp.second }
  66. {}
  67. double operator[] (int i) const { return x[i]; }
  68. const double& operator[] (int i) { return x[i]; }
  69. private:
  70. };
  71. inline mnd::LightDoubleDouble operator+(const mnd::LightDoubleDouble& a,
  72. const mnd::LightDoubleDouble& b)
  73. {
  74. auto[s, e] = mnd::ldd::twoSum(a[0], b[0]);
  75. e += a[1] + b[1];
  76. return mnd::ldd::quickTwoSum(s, e);
  77. }
  78. inline mnd::LightDoubleDouble operator-(const mnd::LightDoubleDouble& a,
  79. const mnd::LightDoubleDouble& b)
  80. {
  81. auto[s, e] = mnd::ldd::twoSum(a[0], -b[0]);
  82. e += a[1] - b[1];
  83. return mnd::ldd::quickTwoSum(s, e);
  84. }
  85. inline mnd::LightDoubleDouble operator*(const mnd::LightDoubleDouble& a,
  86. const mnd::LightDoubleDouble& b)
  87. {
  88. auto[p1, p2] = mnd::ldd::twoProd(a[0], b[0]);
  89. p2 += a[0] * b[1] + a[1] * b[0];
  90. return mnd::ldd::quickTwoSum(p1, p2);
  91. }
  92. struct mnd::LightDoubleFloat
  93. {
  94. float x[2];
  95. inline LightDoubleFloat(double val)
  96. {
  97. x[0] = float(val);
  98. x[1] = float(val - double(x[0]));
  99. }
  100. inline LightDoubleFloat(float u, float l) :
  101. x{ u, l }
  102. {}
  103. inline LightDoubleFloat(mnd::ldd::FloatPair dp) :
  104. x{ dp.first, dp.second }
  105. {}
  106. float operator[] (int i) const { return x[i]; }
  107. const float& operator[] (int i) { return x[i]; }
  108. private:
  109. };
  110. inline mnd::LightDoubleFloat operator+(const mnd::LightDoubleFloat& a,
  111. const mnd::LightDoubleFloat& b)
  112. {
  113. auto[s, e] = mnd::ldd::twoSum(a[0], b[0]);
  114. e += a[1] + b[1];
  115. return mnd::ldd::quickTwoSum(s, e);
  116. }
  117. inline mnd::LightDoubleFloat operator-(const mnd::LightDoubleFloat& a,
  118. const mnd::LightDoubleFloat& b)
  119. {
  120. auto[s, e] = mnd::ldd::twoSum(a[0], -b[0]);
  121. e += a[1] - b[1];
  122. return mnd::ldd::quickTwoSum(s, e);
  123. }
  124. inline mnd::LightDoubleFloat operator*(const mnd::LightDoubleFloat& a,
  125. const mnd::LightDoubleFloat& b)
  126. {
  127. auto[p1, p2] = mnd::ldd::twoProd(a[0], b[0]);
  128. p2 += a[0] * b[1] + a[1] * b[0];
  129. return mnd::ldd::quickTwoSum(p1, p2);
  130. }
  131. #endif // MANDEL_LIGHTDOUBLEDOUBLE_H