FLINT3.7.0-dev
Algorithm

Double-word and multi-double arithmetic

Cost
O(N2)O(N^2) double operations for a product of NN-term expansions, O(N2)O(N^2) for a long division with tapered remainders; about N2N^2 fused multiply-adds dominate.

A floating-point expansion represents a real number as an unevaluated sum x=x0+x1+⋯+xN−1x = x_0 + x_1 + \cdots + x_{N-1} of machine doubles, each much smaller than the previous one. With N=2N = 2 (double-word or double-double arithmetic) this gives about 106 bits of precision, with N=4N = 4 (quad-double) about 212 bits, using only hardware floating-point operations. The idea goes back to Møller [Mol1965] and Dekker [Dek1971]; general expansions are due to Priest [Pri1991] and Shewchuk [She1997], the classical quad-double library is that of Hida, Li and Bailey [HLB2001], and tight error bounds for double-word operations were proved by Joldes, Muller and Popescu [JMP2017]. A comprehensive treatment is in [MBD2018, chapters 4 and 14].

FLINT implements expansions with N=1,…,4N = 1, \ldots, 4 in the dfloat module. Its kernels are designed for ball arithmetic: every operation computes the exact terms of the result with error-free transformations, keeps NN of them, and returns the magnitude of everything it dropped, which becomes the radius of a ball.

Throughout, doubles are IEEE 754 binary64 numbers with round-to-nearest (RN⁡\operatorname{RN}), u=2−53u = 2^{-53} is the unit roundoff, and ulp⁡(x)\operatorname{ulp}(x) is the weight of the last bit of the double xx. For any real tt such that RN⁡(t)\operatorname{RN}(t) is a normal double, RN⁡(t)=t(1+δ)\operatorname{RN}(t) = t(1 + \delta) with ∣δ∣≤u|\delta| \le u.

Error-free transformations#

The sum and the product of two doubles are not doubles in general, but their rounding errors are, and can be computed exactly.

Lemma 1 (Sterbenz). If aa and bb are doubles with b/2≤a≤2bb/2 \le a \le 2b, then a−ba - b is a double, so it is computed exactly [Ste1974].

Algorithm 1: TwoSum and FastTwoSum

TwoSum(a,b)(a, b) [Knu1997; Mol1965]: s←RN⁡(a+b)s \gets \operatorname{RN}(a + b), b′←RN⁡(s−a)b' \gets \operatorname{RN}(s - a), e←RN⁡(RN⁡(a−RN⁡(s−b′))+RN⁡(b−b′))e \gets \operatorname{RN}(\operatorname{RN}(a - \operatorname{RN}(s - b')) + \operatorname{RN}(b - b')).

FastTwoSum(a,b)(a, b) [Dek1971]: s←RN⁡(a+b)s \gets \operatorname{RN}(a + b), e←RN⁡(b−RN⁡(s−a))e \gets \operatorname{RN}(b - \operatorname{RN}(s - a)).

Theorem 2. If a+ba + b does not overflow, TwoSum returns s=RN⁡(a+b)s = \operatorname{RN}(a + b) and ee with s+e=a+bs + e = a + b exactly, using six operations and no branch. FastTwoSum gives the same result in three operations if the exponent of aa is at least that of bb (in particular if ∣a∣≥∣b∣|a| \ge |b|) or a=0a = 0. In both cases ∣e∣≤ulp⁡(s)/2|e| \le \operatorname{ulp}(s)/2.

Proof. For FastTwoSum with ∣a∣≥∣b∣|a| \ge |b|, we first show that z=s−az = s - a is computed exactly. If aa and bb have the same sign, then ∣a∣≤∣s∣≤2∣a∣|a| \le |s| \le 2|a| with ss of the sign of aa, so this follows from Lemma 1. If they have opposite signs and ∣b∣≥∣a∣/2|b| \ge |a|/2, then a+ba + b is exact by the same lemma, so s=a+bs = a + b and z=bz = b. If they have opposite signs and ∣b∣<∣a∣/2|b| < |a|/2, then ∣a∣/2≤∣s∣≤∣a∣|a|/2 \le |s| \le |a| (rounding is monotone and ∣a∣/2|a|/2 is a double), and again Lemma 1 applies. Now b−z=(a+b)−sb - z = (a + b) - s is the rounding error of a nearest-rounded sum of two doubles, which is itself a double (its magnitude is at most ulp⁡(s)/2\operatorname{ulp}(s)/2 and it is a multiple of the ulp of the operand with the smaller exponent), so it is also computed exactly. TwoSum reconstructs the same quantities without knowing which operand is larger; see [MBD2018, §4.3] for the complete proof. Sums are exact in the subnormal range, so no underflow condition is needed.

Algorithm 2: TwoProd

TwoProd(a,b)(a, b): p←RN⁡(ab)p \gets \operatorname{RN}(ab), e←RN⁡(ab−p)e \gets \operatorname{RN}(ab - p) computed with one fused multiply-add.

Theorem 3. If abab does not overflow and ∣ab∣≥2−969|ab| \ge 2^{-969} or ab=0ab = 0, TwoProd returns p+e=abp + e = ab exactly.

Proof. The exact product abab has at most 106 significant bits and is a multiple of ulp⁡(a)ulp⁡(b)\operatorname{ulp}(a)\operatorname{ulp}(b). Its rounding error ab−pab - p is at most ulp⁡(p)/2\operatorname{ulp}(p)/2 in magnitude and is a multiple of the same quantity, so it fits in 53 bits; the condition on ∣ab∣|ab| ensures that this multiple is not below the subnormal range. An FMA rounds the exact ab−pab - p once, which is exact for a double.

Without an FMA, TwoProd can be computed with Dekker's product, which splits each operand into two 26-bit halves (Veltkamp splitting) and costs 17 operations [Dek1971]; _d_vec_dot_thrice uses this form. In C, all of these transformations break if the compiler contracts a separate multiplication and addition into an FMA, or evaluates intermediate results in extended precision (x87). The dfloat module is therefore compiled with -ffp-contract=off and with SSE2 arithmetic, and dfloat_is_supported reports whether these requirements hold.

Expansions and renormalisation#

An expansion (x0,…,xN−1)(x_0, \ldots, x_{N-1}) is nonoverlapping if ∣xi+1∣≤ulp⁡(xi)/2|x_{i+1}| \le \operatorname{ulp}(x_i)/2 for all ii with xi≠0x_i \ne 0, and canonical if in addition zeros occur only at the end. A canonical expansion is obtained from a real number xx by rounding term by term, x0=RN⁡(x)x_0 = \operatorname{RN}(x), x1=RN⁡(x−x0)x_1 = \operatorname{RN}(x - x_0), and so on; it is unique up to ties.

Arithmetic produces a list of terms, ordered by decreasing magnitude but overlapping, which must be converted to NN nonoverlapping components.

Algorithm 3: VecSum (bottom-up renormalisation)

Input: doubles t0,…,tm−1t_0, \ldots, t_{m-1}, roughly decreasing in magnitude.

Output: t0′,…,tm−1′t_0', \ldots, t_{m-1}' with the same exact sum.

  1. For i=m−2,m−3,…,0i = m - 2, m - 3, \ldots, 0: (ti,ti+1)←TwoSum(ti,ti+1)(t_i, t_{i+1}) \gets \text{TwoSum}(t_i, t_{i+1}).

Since each step is error-free, the sum is preserved exactly, and after the pass each ti+1t_{i+1} is the rounding error of a sum whose rounded value is tit_i, so ∣ti+1∣≤ulp⁡(ti)/2|t_{i+1}| \le \operatorname{ulp}(t_i)/2. The result is not necessarily canonical: a cancellation in the sum that produced ti+1t_{i+1} can leave ti+2t_{i+2} larger than ti+1t_{i+1}. FLINT calls this weak normalisation. It is all that the error analysis needs, and it is what the dfloat kernels produce; a second, top-down pass of TwoSums (VecSumErr) followed by a check makes the expansion canonical (dN_canonicalise, or every result in a context with DFLOAT_STRONG). For N=2N = 2 weak normalisation is already canonical. The general renormalisation _dfloat_renorm of an arbitrary number of terms adds a branchy pass (VecSumErrBranch of [JMPT2016]) that removes zero components before nonzero ones.

Addition and multiplication#

The kernels organise the exact terms of a result by order: a term of order kk has magnitude about uku^k times that of the head.

Algorithm 4: Addition of NN-term expansions
  1. For i=0,…,N−1i = 0, \ldots, N-1: (si,ei)←TwoSum(xi,yi)(s_i, e_i) \gets \text{TwoSum}(x_i, y_i).
  2. S0←s0S_0 \gets s_0. For k=1,…,N−1k = 1, \ldots, N-1: accumulate Sk←sk+ek−1+(residuals of order k−1)S_k \gets s_k + e_{k-1} + (\text{residuals of order } k-1) with TwoSums, keeping their residuals as terms of order kk.
  3. Renormalise S0,…,SN−1S_0, \ldots, S_{N-1} with Algorithm 3.
  4. The dropped part is eN−1e_{N-1} plus the residuals of order N−1N-1.
Algorithm 5: Multiplication of NN-term expansions
  1. For i+j<Ni + j < N: (hij,lij)←TwoProd(xi,yj)(h_{ij}, l_{ij}) \gets \text{TwoProd}(x_i, y_j).
  2. S0←h00S_0 \gets h_{00}. For k=1,…,N−1k = 1, \ldots, N-1: accumulate with TwoSums Sk←∑i+j=khij+∑i+j=k−1lij+(residuals of order k−1)S_k \gets \sum_{i+j=k} h_{ij} + \sum_{i+j=k-1} l_{ij} + (\text{residuals of order } k-1).
  3. Renormalise S0,…,SN−1S_0, \ldots, S_{N-1} with Algorithm 3.
  4. The dropped part consists of the residuals of order N−1N - 1, the low parts lijl_{ij} with i+j=N−1i + j = N - 1, and the products xiyjx_i y_j with i+j≥Ni + j \ge N, which are not computed exactly and are bounded by ∣RN⁡(xiyj)∣|\operatorname{RN}(x_i y_j)|.

The products need N(N+1)/2N(N+1)/2 TwoProds, each a multiplication and an FMA. Squaring uses the symmetry hij=hjih_{ij} = h_{ji} (doubling is exact). The product with a single double needs NN TwoProds.

Theorem 4. Let res\mathit{res} be the renormalised result and EE the sum of the absolute values of the dropped terms of Algorithm 4 or Algorithm 5. If no product of nonzero components has magnitude below 2−9692^{-969} and nothing overflows, then ∣x∘y−res∣≤E|x \circ y - \mathit{res}| \le E, where ∘\circ is the exact operation.

Proof. Every step is an error-free transformation by Theorem 2 and Theorem 3, so x∘yx \circ y equals the sum of the kept and the dropped terms exactly, except for the products of order ≥N\ge N, whose exact values satisfy ∣xiyj∣≤∣RN⁡(xiyj)∣(1+u)|x_i y_j| \le |\operatorname{RN}(x_i y_j)|(1 + u); the factor 1+u1 + u and the rounding errors in forming EE itself are absorbed by the slack factor of Lemma 5.

For the plain formats, EE is not computed, and the error is of the order of uNu^N times the magnitude of the result, with small constants [HLB2001; JMP2017]. In the ball formats, EE is added to the radius. When the inputs are not exact, tracking the last-order residuals exactly costs as much as the product itself for N=4N = 4, so the ball products then accumulate the last order with plain additions and bound their rounding errors by uu times the accumulated magnitudes; this loses only a constant factor in a radius that is nonzero anyway, and keeps exact products of exact balls exact.

Radius arithmetic#

The radius of a ball is a double computed in round-to-nearest arithmetic from nonnegative quantities, and is made an upper bound by a single multiplication at the end.

Lemma 5. Let rr be a nonnegative real number obtained from nonnegative doubles by at most 272^7 additions and multiplications, and r~\tilde r the result of performing the same operations in round-to-nearest arithmetic, where no operation has an inexact subnormal result. Then r≤RN⁡(r~(1+2−45))r \le \operatorname{RN}(\tilde r (1 + 2^{-45})).

Proof. Each operation on nonnegative numbers satisfies t≤RN⁡(t)/(1−u)t \le \operatorname{RN}(t)/(1 - u), so by induction r≤r~(1−u)−27≤r~exp⁡(27u(1+u))≤r~(1+2−46+2−90)r \le \tilde r (1 - u)^{-2^7} \le \tilde r \exp(2^7 u (1 + u)) \le \tilde r (1 + 2^{-46} + 2^{-90}). On the other hand RN⁡(r~(1+2−45))≥r~(1+2−45)(1−u)≥r~(1+2−45−2−52)\operatorname{RN}(\tilde r (1 + 2^{-45})) \ge \tilde r (1 + 2^{-45})(1 - u) \ge \tilde r (1 + 2^{-45} - 2^{-52}), which is larger. Sums of doubles in the subnormal range are exact, and products and quotients that could underflow are bumped up by 2−10702^{-1070} (_dfloat_rad_mul), which preserves the inequality.

The ball operations then use the standard propagation bounds. For the product, ∣x′y′−xy∣≤∣x∣ry+∣y∣rx+rxry|x'y' - xy| \le |x| r_y + |y| r_x + r_x r_y for ∣x′−x∣≤rx|x' - x| \le r_x and ∣y′−y∣≤ry|y' - y| \le r_y, with ∣x∣|x| bounded by the sum of the absolute values of the components. For the quotient:

Proposition 6. Let qq be any number and ∣y∣>ry|y| > r_y. For all x′x' and y′y' with ∣x′−x∣≤rx|x' - x| \le r_x and ∣y′−y∣≤ry|y' - y| \le r_y,

∣x′y′−q∣≤∣x−qy∣+rx+∣q∣ry∣y∣−ry.\left|\frac{x'}{y'} - q\right| \le \frac{|x - qy| + r_x + |q| r_y}{|y| - r_y}.

Proof. x′/y′−q=(x′−qy′)/y′x'/y' - q = (x' - qy')/y', with ∣x′−qy′∣≤∣x−qy∣+∣x′−x∣+∣q∣∣y′−y∣|x' - qy'| \le |x - qy| + |x' - x| + |q||y' - y| and ∣y′∣≥∣y∣−ry|y'| \ge |y| - r_y.

The residual x−qyx - qy for the computed quotient qq is enclosed with the tracked kernels, so that an exact quotient of exact balls gets radius zero. For the reciprocal square root, with e=1−xr2e = 1 - x r^2 for the computed rr, the series (1−e)−1/2=∑k(2kk)(e/4)k(1 - e)^{-1/2} = \sum_k \binom{2k}{k} (e/4)^k has positive coefficients and ∑k≥2(2kk)4−k∣e∣k−2≤1/2\sum_{k \ge 2} \binom{2k}{k} 4^{-k} |e|^{k-2} \le 1/2 for ∣e∣≤1/4|e| \le 1/4, so that ∣x−1/2−r∣≤∣r∣(∣e∣/2)(1+∣e∣)|x^{-1/2} - r| \le |r|(|e|/2)(1 + |e|).

Division and square root#

Algorithm 6: Long division with tapered remainders

Input: expansions xx, yy with y0≠0y_0 \ne 0.

Output: q=q0+⋯+qN−1≈x/yq = q_0 + \cdots + q_{N-1} \approx x/y.

  1. r←xr \gets x, v←RN⁡(1/y0)v \gets \operatorname{RN}(1/y_0).
  2. For k=0,…,N−1k = 0, \ldots, N-1:

    1. qk←RN⁡(r0v)q_k \gets \operatorname{RN}(r_0 v) (for the last digit, RN⁡(r0/y0)\operatorname{RN}(r_0/y_0)).
    2. If k<N−1k < N - 1: (p,e)←TwoProd(qk,y0)(p, e) \gets \text{TwoProd}(q_k, y_0), d0←r0−pd_0 \gets r_0 - p (exact), and r←(d0−e)+(r1+⋯ )−qk(y1+⋯ )r \gets (d_0 - e) + (r_1 + \cdots) - q_k (y_1 + \cdots), kept with N−k−1N - k - 1 components.
  3. Renormalise q0,…,qN−1q_0, \ldots, q_{N-1}.

The digit qkq_k is within a relative 2u+u22u + u^2 of r0/y0r_0/y_0, so that p=RN⁡(qky0)p = \operatorname{RN}(q_k y_0) is within a factor 2 of r0r_0 and d0=r0−pd_0 = r_0 - p is exact by Lemma 1: the cancellation of the heads loses no information, and the next remainder absorbs the error of the digit. After step kk the remainder is about uk+1∣x∣u^{k+1}|x| and is only needed to absolute precision uN∣x∣u^N |x|, so it is kept with fewer components (tapered precision); the remainder update is a three-term sum of expansions of the size of the new remainder. A Newton–Karp–Markstein division [KM1997] (a reciprocal at half precision, one product and a correction) turned out to be slower at every NN, because the steps of the long division are cheap products of a double with the divisor and the divisions are off the critical path.

The square root is the Newton iteration s←s+(x−s2)/(2s)s \gets s + (x - s^2)/(2s) from s=RN⁡(x0)s = \operatorname{RN}(\sqrt{x_0}), doubling the number of correct components per step. The residual x−s2x - s^2 is computed as (x0−s02)−(s−s0)(s+s0)+(x1+⋯ )(x_0 - s_0^2) - (s - s_0)(s + s_0) + (x_1 + \cdots) with the head exact (TwoProd and Lemma 1), and the correction is a long division producing only the digits it needs. The reciprocal square root iterates r←r+r(1−xr2)/2r \gets r + r(1 - x r^2)/2 in the same way.

Use in FLINT#

void d2_mul(d2_t res, d2_srcptr x, d2_srcptr y)
void d2_div(d2_t res, d2_srcptr x, d2_srcptr y)
void _d2_mul_tracked(double * res, double * err, const double * x, const double * y)
void _dfloat_renorm(double * res, int n, double * err, double * t, int len)

Referenced from#

References#

  • [Mol1965] O. Møller. Quasi double-precision in floating point addition. BIT 5 (1965), 37–50.
  • [Dek1971] T. J. Dekker. A floating-point technique for extending the available precision. Numerische Mathematik 18 (1971), 224–242. https://doi.org/10.1007/BF01397083
  • [Pri1991] D. M. Priest. Algorithms for arbitrary precision floating point arithmetic. Proceedings of the 10th IEEE Symposium on Computer Arithmetic (ARITH-10), 1991, 132–143.
  • [She1997] J. R. Shewchuk. Adaptive precision floating-point arithmetic and fast robust geometric predicates. Discrete & Computational Geometry 18 (1997), 305–363. https://doi.org/10.1007/PL00009321
  • [HLB2001] Y. Hida, X. S. Li and D. H. Bailey. Algorithms for quad-double precision floating point arithmetic. Proceedings of the 15th IEEE Symposium on Computer Arithmetic (ARITH-15), 2001, 155–162.
  • [JMP2017] M. Joldes, J.-M. Muller and V. Popescu. Tight and rigorous error bounds for basic building blocks of double-word arithmetic. ACM Transactions on Mathematical Software 44:2 (2017), 15:1–15:27. https://doi.org/10.1145/3121432
  • [MBD2018] J.-M. Muller, N. Brunie, F. de Dinechin, C.-P. Jeannerod, M. Joldes, V. Lefèvre, G. Melquiond, N. Revol and S. Torres, Handbook of Floating-Point Arithmetic, second edition, Birkhäuser (2018), https://doi.org/10.1007/978-3-319-76526-6
  • [Ste1974] P. H. Sterbenz. Floating-Point Computation. Prentice-Hall, 1974.
  • [Knu1997] Knuth, D. E. The Art of Computer Programming, volume 2: Seminumerical algorithms, 1997
  • [JMPT2016] M. Joldes, O. Marty, J.-M. Muller and V. Popescu. Arithmetic algorithms for extended precision using floating-point expansions. IEEE Transactions on Computers 65:4 (2016), 1197–1210. https://doi.org/10.1109/TC.2015.2441714
  • [KM1997] A. H. Karp and P. Markstein, "High-precision division and square root", ACM Transactions on Mathematical Software 23:4 (1997), 561–589
  • [ORO2005] T. Ogita, S. M. Rump and S. Oishi. Accurate sum and dot product. SIAM Journal on Scientific Computing 26:6 (2005), 1955–1988. https://doi.org/10.1137/030601818
Cite this page

The FLINT team, “Double-word and multi-double arithmetic,” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/algorithms/floating-point/double-word.html (generated 2026-11-02).