|  | @@ -0,0 +1,105 @@
 | 
	
		
			
				|  |  | +#ifndef MANDEL_LIGHTDOUBLEDOUBLE_H
 | 
	
		
			
				|  |  | +#define MANDEL_LIGHTDOUBLEDOUBLE_H
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <utility>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +namespace mnd
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    struct LightDoubleDouble;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    namespace ldd
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        using DoublePair = std::pair<double, double>;
 | 
	
		
			
				|  |  | +        inline static DoublePair quickTwoSum(double a, double b)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            double s = a + b;
 | 
	
		
			
				|  |  | +            double e = b - (s - a);
 | 
	
		
			
				|  |  | +            return { s, e };
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        inline DoublePair twoSum(double a, double b)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            double s = a + b;
 | 
	
		
			
				|  |  | +            double v = s - a;
 | 
	
		
			
				|  |  | +            double e = (a - (s - v)) + (b - v);
 | 
	
		
			
				|  |  | +            return { s, e };
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        inline DoublePair split(double a)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            static const double splitter = double((1ULL << 27) + 1);
 | 
	
		
			
				|  |  | +            double t = splitter * a;
 | 
	
		
			
				|  |  | +            double ahi = t - (t - a);
 | 
	
		
			
				|  |  | +            double alo = a - ahi;
 | 
	
		
			
				|  |  | +            return { ahi, alo };
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        inline DoublePair twoProd(double a, double b)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            double p = a * b;
 | 
	
		
			
				|  |  | +            auto [ahi, alo] = split(a);
 | 
	
		
			
				|  |  | +            auto [bhi, blo] = split(b);
 | 
	
		
			
				|  |  | +            double e = ((ahi * bhi - p) + ahi * blo + alo * bhi) + alo * blo;
 | 
	
		
			
				|  |  | +            return { p, e };
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        inline DoublePair twoProdFma(double a, double b)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            double p = a * b;
 | 
	
		
			
				|  |  | +            double e = std::fma(a, b, -p);
 | 
	
		
			
				|  |  | +            return { p, e };
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct mnd::LightDoubleDouble
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    double x[2];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    inline LightDoubleDouble(double val) :
 | 
	
		
			
				|  |  | +        x{ val, 0 }
 | 
	
		
			
				|  |  | +    {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    inline LightDoubleDouble(double u, double l) :
 | 
	
		
			
				|  |  | +        x{ u, l }
 | 
	
		
			
				|  |  | +    {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    inline LightDoubleDouble(mnd::ldd::DoublePair dp) :
 | 
	
		
			
				|  |  | +        x{ dp.first, dp.second }
 | 
	
		
			
				|  |  | +    {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    double operator[]           (int i) const   { return x[i]; }
 | 
	
		
			
				|  |  | +    const double& operator[]    (int i)         { return x[i]; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +private:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline mnd::LightDoubleDouble operator+(const mnd::LightDoubleDouble& a,
 | 
	
		
			
				|  |  | +    const mnd::LightDoubleDouble& b)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    auto[s, e] = mnd::ldd::twoSum(a[0], b[0]);
 | 
	
		
			
				|  |  | +    e += a[1] + b[1];
 | 
	
		
			
				|  |  | +    return mnd::ldd::quickTwoSum(s, e);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline mnd::LightDoubleDouble operator-(const mnd::LightDoubleDouble& a,
 | 
	
		
			
				|  |  | +    const mnd::LightDoubleDouble& b)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    auto[s, e] = mnd::ldd::twoSum(a[0], -b[0]);
 | 
	
		
			
				|  |  | +    e += a[1] - b[1];
 | 
	
		
			
				|  |  | +    return mnd::ldd::quickTwoSum(s, e);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline mnd::LightDoubleDouble operator*(const mnd::LightDoubleDouble& a,
 | 
	
		
			
				|  |  | +    const mnd::LightDoubleDouble& b)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    auto[p1, p2] = mnd::ldd::twoProd(a[0], b[0]);
 | 
	
		
			
				|  |  | +    p2 += a[0] * b[1] + a[1] * b[0];
 | 
	
		
			
				|  |  | +    return mnd::ldd::quickTwoSum(p1, p2);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#endif // MANDEL_LIGHTDOUBLEDOUBLE_H
 |