#ifndef MANDEL_QUADDOUBLE_H #define MANDEL_QUADDOUBLE_H #include "PolyfloatUtil.h" namespace mnd { struct QuadDouble; inline mnd::pfu::Quadruple renorm2(double x0, double x1, double x2, double x3, double x4) { auto [st1, t4] = mnd::pfu::quickTwoSum(x3, x4); auto [st2, t3] = mnd::pfu::quickTwoSum(x2, st1); auto [st3, t2] = mnd::pfu::quickTwoSum(x1, st2); auto [t0, t1] = mnd::pfu::quickTwoSum(x0, st3); auto e = t0; auto [r0, e1] = mnd::pfu::quickTwoSum(e, t1); auto [r1, e2] = mnd::pfu::quickTwoSum(e1, t2); auto [r2, e3] = mnd::pfu::quickTwoSum(e2, t3); auto r3 = e3 + t4; return { r0, r1, r2, r3 }; } } struct mnd::QuadDouble { double x[4]; inline QuadDouble(double val) : x{ val, 0.0, 0.0, 0.0 } {} inline QuadDouble(double a, double b, double c, double d) : x{ a, b, c, d } {} double operator[] (int i) const { return x[i]; } const double& operator[] (int i) { return x[i]; } }; inline mnd::QuadDouble operator+(const mnd::QuadDouble& a, const mnd::QuadDouble& b) { auto[s0, e0] = mnd::pfu::twoSum(a[0], b[0]); auto[s1, e1] = mnd::pfu::twoSum(a[1], b[1]); auto[s2, e2] = mnd::pfu::twoSum(a[2], b[2]); auto[s3, e3] = mnd::pfu::twoSum(a[3], b[3]); auto r0 = s0; auto [r1, t0] = mnd::pfu::twoSum(s1, e0); auto [r2, t1, t2] = mnd::pfu::threeSum(s2, e1, t0); auto [r3, t3, _t4] = mnd::pfu::threeSum(s3, e2, t1); auto [r4, _t5, _t6] = mnd::pfu::threeSum(e3, t3, t2); auto[re0, er1] = mnd::pfu::quickTwoSum(r0, r1); auto[re1, er2] = mnd::pfu::quickTwoSum(er1, r2); auto[re2, er3] = mnd::pfu::quickTwoSum(er2, r3); auto[re3, er4] = mnd::pfu::quickTwoSum(er3, r4); return { re0, re1, re2, re3 }; } inline bool operator>(const mnd::QuadDouble& a, const mnd::QuadDouble& b) { if (a[0] > b[0]) return true; if (a[0] < b[0]) return false; if (a[1] > b[1]) return true; if (a[1] < b[1]) return false; if (a[2] > b[2]) return true; if (a[2] < b[2]) return false; return a[3] > b[3]; } inline mnd::QuadDouble operator-(const mnd::QuadDouble& a, const mnd::QuadDouble& b) { return a + mnd::QuadDouble{ -b[0], -b[1], -b[2], -b[3] }; } inline mnd::QuadDouble operator*(const mnd::QuadDouble& a, const mnd::QuadDouble& b) { auto[a0, b0] = mnd::pfu::twoProd(a[0], b[0]); auto[b1, c0] = mnd::pfu::twoProd(a[0], b[1]); auto[b2, c1] = mnd::pfu::twoProd(a[1], b[0]); auto[c2, d0] = mnd::pfu::twoProd(a[0], b[2]); auto[c3, d1] = mnd::pfu::twoProd(a[1], b[1]); auto[c4, d2] = mnd::pfu::twoProd(a[2], b[0]); auto d5 = a[3] * b[0]; auto d6 = a[2] * b[1]; auto d7 = a[1] * b[2]; auto d8 = a[0] * b[3]; auto r0 = a0; auto[r1, c5, d3] = mnd::pfu::threeSum(b0, b1, b2); auto[r2, d4, e0] = mnd::pfu::sixThreeSum(c0, c1, c2, c3, c4, c5); auto[r3, e1, ex_] = mnd::pfu::nineThreeSum(d0, d1, d2, d3, d4, d5, d6, d7, d8); auto r4 = e0 + e1; auto [n0, n1, n2, n3] = mnd::renorm2(r0, r1, r2, r3, r4); return { n0, n1, n2, n3 }; } #endif // MANDEL_QUADDOUBLE_H