1
0

LightDoubleDouble.h 3.8 KB

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