/*- * Copyright (c) 2005 Colin Percival * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted providing that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Redistributions of source code must ensure that the list of * copyright notices is complete, and the lack of a copyright notice * corresponding to a copyrightable contribution or modification may * be taken as an affirmative statement that said contribution or * modification has been placed in the public domain. * 4. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Colin Percival. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef RCSID static const char rcsid[] = "$Id: roots.c,v 1.1 2005/07/04 01:47:29 cperciva Exp $"; #endif #include #include #include "roots.h" /**T \section{Correctly rounded double-precision constants} A value $x$ can be converted into a correctly rounded double precision floating-point constant via the following MAPLE code: \begin{verbatimtab} r := proc(x) global Digits; local y, sgn, pow, mant; if x = 0 then RETURN("0.0"); fi; Digits := 30; sgn := sign(evalf(x)); pow := floor(log[2.](x * sgn)); y := evalf(x * sgn * 2^(52 - pow)); if abs(y - round(y)) > 0.49999 then RETURN("CANNOT ROUND, NEED MORE DIGITS"); fi; if sgn > 0 then sgn := "0x1."; else sgn := "-0x1."; fi; cat(sgn, substring(convert(round(y), hex), 2..-1), "p", pow); end; \end{verbatimtab} Values which are more than $0.49999 \ulp$ away from from the nearest representable double precision floating-point value will output an error message, in which case the parameters $30$ and $0.49999$ should be increased. \section{Values of $\exp(i \pi / 2^n) - 1$} The table {\em omc\_s} is generated by the following MAPLE code: \begin{verbatimtab} for n from 7 to 29 do printf("%s, %s,\n", r(cos(2 * Pi / 2^n) - 1), r(sin(2 * Pi / 2^n))); od; \end{verbatimtab} and, taking $w_{k + 7} = \textrm{omc\_s}_{2 k} + i \textrm{omc\_s}_{2 k + 1}$, satisfies $$ w_k \approx \exp(2 i \pi / 2^k) - 1 $$ for $7 \leq k \leq 29$. */ static double omc_s[] = { -0x1.3BC390D250439p-10, 0x1.91F65F10DD814p-5, -0x1.3BCFBD9979A27p-12, 0x1.92155F7A3667Ep-6, -0x1.3BD2C8DA49511p-14, 0x1.921D1FCDEC784p-7, -0x1.3BD38BAB6D94Cp-16, 0x1.921F0FE670071p-8, -0x1.3BD3BC5FC5AB4p-18, 0x1.921F8BECCA4BAp-9, -0x1.3BD3C88CDCA13p-20, 0x1.921FAAEE6472Ep-10, -0x1.3BD3CB98226DCp-22, 0x1.921FB2AECB360p-11, -0x1.3BD3CC5AF3E1Dp-24, 0x1.921FB49EE4EA6p-12, -0x1.3BD3CC8BA83EEp-26, 0x1.921FB51AEB57Cp-13, -0x1.3BD3CC97D5562p-28, 0x1.921FB539ECF31p-14, -0x1.3BD3CC9AE09BFp-30, 0x1.921FB541AD59Ep-15, -0x1.3BD3CC9BA36D7p-32, 0x1.921FB5439D73Ap-16, -0x1.3BD3CC9BD421Cp-34, 0x1.921FB544197A1p-17, -0x1.3BD3CC9BE04EEp-36, 0x1.921FB544387BAp-18, -0x1.3BD3CC9BE35A2p-38, 0x1.921FB544403C1p-19, -0x1.3BD3CC9BE41CFp-40, 0x1.921FB544422C2p-20, -0x1.3BD3CC9BE44DBp-42, 0x1.921FB54442A83p-21, -0x1.3BD3CC9BE459Dp-44, 0x1.921FB54442C73p-22, -0x1.3BD3CC9BE45CEp-46, 0x1.921FB54442CEFp-23, -0x1.3BD3CC9BE45DAp-48, 0x1.921FB54442D0Ep-24, -0x1.3BD3CC9BE45DDp-50, 0x1.921FB54442D16p-25, -0x1.3BD3CC9BE45DEp-52, 0x1.921FB54442D18p-26, -0x1.3BD3CC9BE45DEp-54, 0x1.921FB54442D18p-27, }; /**T \pagebreak \section{Values of $\exp(2 k i \pi / 2^6)$} The table {\em c\_s} was constructed by the following MAPLE code: \begin{verbatimtab} for k from 0 to 8 do printf("%s, %s,\n", r(cos(2 * Pi * k / 2^6)), r(sin(2 * Pi * k / 2^6))); od; \end{verbatimtab} and, taking $w_k = \textrm{c\_s}_{2 k} + i \textrm{c\_s}_{2 k + 1}$, satisfies $$ w_k \approx \exp(2 k i \pi / 2^6) $$ for $0 \leq k \leq 8$. */ static double c_s[] = { 0x1.0000000000000p0, 0.0, 0x1.FD88DA3D12526p-1, 0x1.917A6BC29B42Cp-4, 0x1.F6297CFF75CB0p-1, 0x1.8F8B83C69A60Bp-3, 0x1.E9F4156C62DDAp-1, 0x1.294062ED59F06p-2, 0x1.D906BCF328D46p-1, 0x1.87DE2A6AEA963p-2, 0x1.C38B2F180BDB1p-1, 0x1.E2B5D3806F63Bp-2, 0x1.A9B66290EA1A3p-1, 0x1.1C73B39AE68C8p-1, 0x1.8BC806B151741p-1, 0x1.44CF325091DD6p-1, 0x1.6A09E667F3BCDp-1, 0x1.6A09E667F3BCDp-1, }; /**T \section{Computation of $\exp(2 k i \pi / 2^{29})$} We make use of the following three recurrences: \begin{enumerate} \item $\exp(i (x + \pi / 4)) = i \cdot {\rm conjugate}(\exp(i (\pi / 4 - x)))$. \item For $k$ not a multiple of $2^{n - 6}$, $0 \leq k < 2^{n - 3}$, $0 \leq q < 2^3$, $0 < r < 2^{n - 6}$, $k = q 2^{n - 6} + r$, $$ \exp(2 \pi i k / 2^n) = \exp(2 \pi i q / 2^6) + \exp(2 \pi i q / 2^6) \cdot (\exp(2 \pi i r / 2^n) - 1) $$ \item For $2^{n - m} < k < 2^{n - m + 1} \leq 2^{n - 6}$, $k = 2^{n - m} + r$, $$ \exp(2 \pi i k / 2^n) - 1 = x_0 + x_1 + x_0 x_1 $$ where $x_0 = \exp(2 \pi i / 2^m) - 1$, $x_1 = \exp(2 \pi i r / 2^n) - 1$. \end{enumerate} and note that, together with tables of $\exp(2 \pi i k / 2^6)$ for $0 \leq k \leq 2^3$ and $\exp(2 \pi i / 2^m) - 1$ for ${7 \leq m \leq 29}$, these permit the computation of $\exp(2 \pi i k / 2^{29})$ for $0 \leq k < 2^{27}$. The function {\em expm1\_tbl}($LUT$, $n$, $m$) computes the complex values $\exp(2 \pi i k / 2^{m + 7}) - 1$ for $0 \leq k < 2^n$ and writes them into $LUT$. The inputs must satisfy $0 \leq m \leq 22$, $0 \leq n \leq m + 1$, and $LUT$ must have space to store $2^{n + 1}$ doubles (i.e., $2^{n + 4}$ bytes). */ static void expm1_tbl(double * LUT, int n, int m) { double x0r, x0i, x1r, x1i; uint32_t i, N; if (n == 0) { LUT[0] = 0.0; LUT[1] = 0.0; } else { expm1_tbl(LUT, n - 1, m); x0r = omc_s[2 * (m + 1 - n)]; x0i = omc_s[2 * (m + 1 - n) + 1]; N = 1 << (n - 1); for (i = 0; i < N; i++) { x1r = LUT[2 * i]; x1i = LUT[2 * i + 1]; LUT[2 * (i + N)] = x0r + (x1r + (x0r * x1r - x0i * x1i)); LUT[2 * (i + N) + 1] = x0i + (x1i + (x0r * x1i + x0i * x1r)); } } } /**T \begin{lemma} Given $LUT$ as produced by {\em expm1\_tbl}($LUT$, $n$, $m$) and making the assignment ${w_k = LUT_{2 k} + i LUT_{2 k + 1}}$, $$ \abs{w_k + 1 - \exp(2 \pi i k / 2^{m + 7})} < 12.75 \epsilon \cdot 2^n / 2^{m + 7} + \sum_{j = m + 1 - n}^{m}{\abs{W_j - \widehat{W}_j}} $$ for all $0 \leq k < 2^n$, where $W_j = \exp(2 \pi i / 2^{j + 7}) - 1$ and $\widehat{W}_j$ is the value of $W_j$ as stored in {\em omc\_s}. Further, if $n = m + 1$, then $$ \abs{w_k + 1 - \exp(2 \pi i k / 2^{m + 7})} < 14 \epsilon / 64 $$ for all $0 \leq k < 2^n$. \end{lemma} \begin{proof} We prove the first part by induction. If $n = 0$, then there is clearly no error, and the result holds. Now assume that the result holds for $n = n_0 \leq m$, and consider the behaviour of {\em expm1\_tbl}($LUT$, $n_0 + 1$, $m$). Since {\em expm1\_tbl}($LUT$, $n_0 + 1$, $m$) calls {\em expm1\_tbl}($LUT$, $n_0$, $m$) and does not subsequently modify the first $2^{n_0}$ complex values stored in $LUT$, the required result holds for $0 \leq k < 2^{n_0}$; consequently, we need only prove that the result holds for $2^{n_0} \leq k < 2^{n_0 + 1}$. For such a $k$, $w_k$ is computed as $$ w_k := x_0 + \left( w_{k - 2^{n_0}} + x_0 w_{k - 2^{n_0}} \right) $$ and where $x_0$ is the value of $\exp(2 i \pi 2^{n_0} / 2^{m + 7}) - 1$ obtained from {\em omc\_s}. The error in $w_k$ is therefore the sum of the following: \begin{enumerate} \item The error introduced in computing the complex product $x_0 w_{k - 2^{n_0}}$. The relative error in computing a complex product less than $\epsilon \sqrt{5}$~\cite{BPZ05}, so this error is less than $\epsilon \sqrt{5} \abs{x_0} \abs{w_{k - 2^{n_0}}}$. Since $\abs{\exp(i x) - 1} < x$ for $x > 0$, we note that $\abs{w_{k - 2^{n_0}}} \leq \abs{x_0} \leq 2 \pi 2^{n_0} / 2^{m + 7} \leq \pi / 64$, and consequently the error introduced in computing the complex product is less than $\epsilon \sqrt{5} (\pi / 64)^2 2^{n_0} / 2^{m}$. \item The error introduced in the addition of $w_{k - 2^{n_0}}$ and $x_0 w_{k - 2^{n_0}}$. The real and imaginary parts of this error are bounded by half of the $\ulp$ of the real and imaginary parts of the result respectively. Since the result of this addition is approximately equal to $\exp(2 \pi i k / 2^{m + 7}) - \exp(2 \pi i 2^{n_0} / 2^{m + 7})$, the real error is bounded by \begin{align*} \frac{1}{2} \ulp(\cos(2 \pi 2^{n_0 + 1} / 2^{m + 7}) - \cos(2 \pi 2^{n_0} / 2^{m + 7})) & = \frac{1}{2} \ulp\left( \frac{3 (2 \pi 2^{n_0 - m - 7})^2}{2} \right) \\ & = \frac{1}{2} \ulp( 2^{2 n_0 - 2 m - 9} ) \\ & = \epsilon 2^{2 n_0 - 2 m - 9} \end{align*} noting that the value within $\ulp()$ can be approximated without changing the result. Similarly, the real error is bounded by \begin{align*} \frac{1}{2} \ulp(\sin(2 \pi 2^{n_0 + 1} / 2^{m + 7}) - \sin(2 \pi 2^{n_0} / 2^{m + 7})) & = \frac{1}{2} \ulp(2 \pi 2^{n_0} / 2^{m + 7}) \\ & = \epsilon 2^{n_0 - m - 5} \end{align*} and thus the absolute complex error is bounded by \begin{align*} \epsilon \sqrt{\left(2^{2 n_0 - 2 m - 9}\right)^2 + \left(2^{n_0 - m - 5}\right)^2} & = \epsilon 2^{n_0 - m - 5} \sqrt{1 + 2^{2 n_0 - 2 m - 8}} \\ & \leq \epsilon 2^{n_0 - m - 5} \sqrt{\frac{257}{256}} \leq 1.002 \epsilon \cdot 2^{n_0 - m - 5} \end{align*} \item The error introduced in computing the sum of $x_0$ and $w_{k - 2^{n_0}} + x_0 w_{k - 2^{n_0}}$. Following the same argument as above, the real error is bounded by \begin{align*} \frac{1}{2} \ulp(\cos(2 \pi 2^{n_0 + 1} / 2^{m + 7}) - 1)) & = \frac{1}{2} \ulp(\frac{(2 \pi 2^{n_0 + 1} / 2^{m + 7})^2}{2}) \\ & = \epsilon 2^{2 n_0 - 2 m - 8} \end{align*} and the imaginary error is bounded by \begin{align*} \frac{1}{2} \ulp(\sin(2 \pi 2^{n_0 + 1} / 2^{m + 7})) & = \frac{1}{2} \ulp(2 \pi 2^{n_0 + 1} / 2^{m + 7}) \\ & = \epsilon 2^{n_0 - m - 4} \end{align*} and consequently the absolute complex error is bounded by \begin{align*} \epsilon \sqrt{\left(2^{2 n_0 - 2 m - 8}\right)^2 + \left(2^{n_0 - m - 4}\right)^2} & = \epsilon2^{n_0 - m - 4} \sqrt{1 + 2^{2 n_0 - 2 m - 8}} \\ & \leq \epsilon 2^{n_0 - m - 4} \sqrt{\frac{257}{256}} \leq 1.002 \epsilon \cdot 2^{n_0 - m - 4} \end{align*} \item The error introduced from inaccuracy in the input $x_0$. This is $\abs{W_{m - n_0} - \widehat{W}_{m - n_0}}$ for $W$ as defined earlier. \item The error introduced from inaccuracy in $w_{k - 2^{n_0}}$. By assumption, this is bounded by $$ 12.75 \epsilon \cdot 2^{n_0} / 2^{m + 7} + \sum_{j = m + 1 - n_0}^{m}{\abs{W_j - \widehat{W}_j}} $$ \end{enumerate} Adding these together, we obtain \begin{align*} \abs{w_k + 1 - \exp(2 \pi i k / 2^{m + 7})} & < \epsilon \left(12 \cdot 1.002 + \frac{\pi^2 \sqrt{5}}{32}\right) 2^{n_0} / 2^{m + 7} + \abs{W_{m - n_0} - \widehat{W}_{m - n_0}} \\ & \qquad + 12.75 \epsilon \cdot 2^{n_0} / 2^{m + 7} + \sum_{j = m + 1 - n_0}^{m}{\abs{W_j - \widehat{W}_j}} \\ & < 12.75 \epsilon \cdot 2^{n_0 + 1} / 2^{m + 7} + \sum_{j = m - n_0}^{m}{\abs{W_j - \widehat{W}_j}} \end{align*} for all $2^{n_0} \leq k < 2^{n_0 + 1}$ and the result follows. To establish the second part of the proof, we compute the sum using the following MAPLE code \begin{verbatimtab} Digits := 50; ERR_e := proc(x) local y, pow; if x = 0 then RETURN(0); fi; y := abs(x); pow := floor(log[2.](y)); evalf(y - round(y * 2^(52 - pow)) * 2^(pow - 52)) * 2^53; end; ERR_c := z -> sqrt(ERR_e(Re(z))^2 + ERR_e(Im(z))^2); sum( ERR_c(exp(2 * Pi * I / 2^n) - 1), n = 7..29); \end{verbatimtab} and obtain $0.01689\ldots \epsilon < 1.25 \epsilon / 64$; adding this to the other $12.75 \epsilon / 64$ provides the stated bound. \end{proof} The function {\em tricl\_roots\_makelut}($LUT$, $n$) computes the complex values $\exp(2 \pi i k / 2^n)$ for ${0 \leq k < 2^{n - 2}}$. The value $n$ must satisfy $2 \leq n \leq 29$, and $LUT$ must have space to store $2^{n - 1}$ doubles (i.e., $2^{n + 2}$ bytes). */ void tricl_roots_makelut(double * LUT, int n) { double x0r, x0i, x1r, x1i; int32_t i, j, N; assert(2 <= n && n <= 29); if (n == 2) { /* We only want k = 0 */ LUT[0] = 1.0; LUT[1] = 0.0; } else if (n <= 6) { /* Copy values of exp(i x) for 0 <= x < pi / 4 from c_s[] */ N = 1 << (6 - n); for (i = 0; i < (1 << (n - 3)); i++) { LUT[2 * i] = c_s[2 * i * N]; LUT[2 * i + 1] = c_s[2 * i * N + 1]; } /* Copy value of exp(i pi / 4) */ LUT[2 * (1 << (n - 3))] = c_s[2 * 8]; LUT[2 * (1 << (n - 3)) + 1] = c_s[2 * 8 + 1]; /*- * Continue by noting that * exp(i (x + pi / 4)) = i conj(exp(i (pi / 4 - x))) */ for (i = (1 << (n - 3)) + 1; i < (1 << (n - 2)); i++) { LUT[2 * i + 1] = LUT[2 * ((1 << (n - 2)) - i)]; LUT[2 * i] = LUT[2 * ((1 << (n - 2)) - i) + 1]; } } else { /* * Compute exp(2 pi i k / 2^n) - 1 for 0 <= k < 2^(n - 6) */ expm1_tbl(LUT, n - 6, n - 7); /* * Combine with appropriate exp(2 pi i k / 2^6) to * obtain exp(2 pi i k / 2^n) for 0 <= k < 2^(n - 3) */ N = 1 << (n - 6); for (i = 7; i >= 0; i--) { for (j = 0; j < N; j++) { x0r = c_s[2 * i]; x0i = c_s[2 * i + 1]; x1r = LUT[2 * j]; x1i = LUT[2 * j + 1]; LUT[2 * (i * N + j)] = x0r + (x0r * x1r - x0i * x1i); LUT[2 * (i * N + j) + 1] = x0i + (x0r * x1i + x0i * x1r); } } /* Copy value of exp(i pi / 4) */ LUT[2 * (1 << (n - 3))] = c_s[2 * 8]; LUT[2 * (1 << (n - 3)) + 1] = c_s[2 * 8 + 1]; /*- * Continue by noting that * exp(i (x + pi / 4)) = i conj(exp(i (pi / 4 - x))) */ for (i = (1 << (n - 3)) + 1; i < (1 << (n - 2)); i++) { LUT[2 * i + 1] = LUT[2 * ((1 << (n - 2)) - i)]; LUT[2 * i] = LUT[2 * ((1 << (n - 2)) - i) + 1]; } } return; } /**T \begin{theorem} Given $LUT$ as produced by {\em tricl\_roots\_makelut}($LUT$, $n$) with $2 \leq n \leq 29$, and making the assignment ${w_k = LUT_{2 k} + i LUT_{2 k + 1}}$, $$ \abs{w_k - \exp(2 \pi i k / 2^n)} < \frac{3}{2} \epsilon $$ for all $0 \leq k < 2^{n - 2}$. \end{theorem} \begin{proof} For $n = 2$, there is only one value produced, and it is given exactly. For $2 < n \leq 6$, the values are copied from the table {\em c\_s}, and the maximum error is trivially $\sqrt{1/2} \epsilon$, well below the bound to be proven. We therefore need only consider the third case in the code, where $n > 6$. In this case, the value $w_k$ is computed as $x_0 + x_0 x_1$, where $x_0$ is the $2^6$th root of unity $\exp(2 \pi i k^\prime / 2^6)$ for $k^\prime = \floor{k / 2^{n - 6}}$, as stored in the table {\em c\_s}, and $x_1$ is the value $\exp(2 \pi i (k - k^\prime 2^{n - 6}) / 2^{n}) - 1$ as generated by {\em expm1\_tbl}($LUT$, $n - 6$, $n - 7$). The error in the values computed is consequently the sum of the following: \begin{enumerate} \item The error introduced from inaccuracy in $x_0$. Since $\abs{1 + x_1} = 1$, this has the same norm as the error in the stored value of $x_0$, i.e., one of $8$ possible values depending upon $k^\prime$. \item The error introduced from inaccuracy in $x_1$. Since $\abs{x_0} = 1$, this has the same norm as the error in the computed value of $x_1$, which is bounded from above by $14 \epsilon / 64$ as shown in Lemma 1. \item The error introduced by rounding errors in computing $x_0 + x_0 x_1$. The real and imaginary parts of this each consist of four elements: Two errors introduced by multiplications in computing the complex product $x_0 x_1$; the error introduced by the addition used in computing the complex product $x_0 x_1$; and the error introduced by the addition of $x_0$ and $x_0 x_1$. Considering the largest possible values at each point in the computation, we note that the real part of this introduced error is bounded by \begin{align*} & \frac{1}{2}\ulp(\cos(2 \pi k^\prime / 2^n)) + \frac{1}{2}\ulp(\cos(2 \pi k^\prime / 2^n) - \cos(2 \pi (k^\prime + 1) / 2^n)) \\ & \qquad + \frac{1}{2}\ulp(\cos(2 \pi k^\prime / 2^n) (1 - \cos(2 \pi / 2^n))) + \frac{1}{2}\ulp(\sin(2 \pi k^\prime / 2^n) \sin(2 \pi / 2^n))) \end{align*} and the imaginary part is bounded by \begin{align*} & \frac{1}{2}\ulp(\sin(2 \pi (k^\prime + 1)/ 2^n)) + \frac{1}{2}\ulp(\sin(2 \pi (k^\prime + 1) / 2^n) - \sin(2 \pi k^\prime / 2^n)) \\ & \qquad + \frac{1}{2}\ulp(\sin(2 \pi k^\prime / 2^n) (1 - \cos(2 \pi / 2^n))) + \frac{1}{2}\ulp(\cos(2 \pi k^\prime / 2^n) \sin(2 \pi / 2^n))) \end{align*} For each of the $8$ possible values of $k^\prime$, these two bounds can be computed, and thereby a bound on the largest absolute error introduced by new rounding errors. \end{enumerate} By computation, the sum of the bounds given above is maximized for $k^\prime = 6$, where we obtain the maximum error bound of $1.488\ldots \epsilon$, below the required bound of $1.5 \epsilon$. \end{proof} \begin{theorem} The $2^n$th roots of unity can be computed in double precision using $2 n + 6$ precomputed values and $\frac{37}{32} 2^n$ double precision floating-point operations, with a maximum absolute error of less than $1.5 \epsilon$. \end{theorem} \begin{proof} The function {\em tricl\_roots\_makelut} behaves as required. \end{proof} For arbitrary precisions, the precise error bound will vary (since the precise errors in the precomputed constants will be different), but will always be less than $2 \epsilon$ for the relevant $\epsilon$. \bibliographystyle{amsplain} \begin{thebibliography}{X} \bibitem{BPZ05} R.P.~Brent, C.~Percival, P.~Zimmermann, \textit{Error Bounds on Complex Floating-Point Multiplication}, manuscript. \end{thebibliography} */