Rational Functions: 5.4 Complex Arithmetic
Rational Functions: 5.4 Complex Arithmetic
Chapter 5.
Evaluation of Functions
Rational Functions
You evaluate a rational function like R(x) = p0 + p1 x + + p x P (x) = Q (x) q0 + q1 x + + q x (5.3.4)
Sample page from NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5) Copyright (C) 1988-1992 by Cambridge University Press. Programs Copyright (C) 1988-1992 by Numerical Recipes Software. Permission is granted for internet users to make one paper copy for their own personal use. Further reproduction, or any copying of machinereadable files (including this one) to any server computer, is strictly prohibited. To order Numerical Recipes books or CDROMs, visit website http://www.nr.com or call 1-800-872-7423 (North America only), or send email to [email protected] (outside North America).
in the obvious way, namely as two separate polynomials followed by a divide. As a matter of convention one usually chooses q 0 = 1, obtained by dividing numerator and denominator by any other q 0 . It is often convenient to have both sets of coefcients stored in a single array, and to have a standard function available for doing the evaluation:
double ratval(double x, double cof[], int mm, int kk) Given mm, kk, and cof[0..mm+kk] , evaluate and return the rational function (cof[0] +
CITED REFERENCES AND FURTHER READING: Acton, F.S. 1970, Numerical Methods That Work; 1990, corrected edition (Washington: Mathematical Association of America), pp. 183, 190. [1] Mathews, J., and Walker, R.L. 1970, Mathematical Methods of Physics, 2nd ed. (Reading, MA: W.A. Benjamin/Addison-Wesley), pp. 361363. [2] Knuth, D.E. 1981, Seminumerical Algorithms, 2nd ed., vol. 2 of The Art of Computer Programming (Reading, MA: Addison-Wesley), 4.6. [3] Fike, C.T. 1968, Computer Evaluation of Mathematical Functions (Englewood Cliffs, NJ: PrenticeHall), Chapter 4. Winograd, S. 1970, Communications on Pure and Applied Mathematics, vol. 23, pp. 165179. [4] Kronsjo, L. 1987, Algorithms: Their Complexity and Efciency, 2nd ed. (New York: Wiley). [5]
177
Actually, complex arithmetic is not quite trivial. Addition and subtraction are done in the obvious way, performing the operation separately on the real and imaginary parts of the operands. Multiplication can also be done in the obvious way, with 4 multiplications, one addition, and one subtraction, (a + ib)(c + id) = (ac bd) + i(bc + ad) (5.4.1)
Sample page from NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5) Copyright (C) 1988-1992 by Cambridge University Press. Programs Copyright (C) 1988-1992 by Numerical Recipes Software. Permission is granted for internet users to make one paper copy for their own personal use. Further reproduction, or any copying of machinereadable files (including this one) to any server computer, is strictly prohibited. To order Numerical Recipes books or CDROMs, visit website http://www.nr.com or call 1-800-872-7423 (North America only), or send email to [email protected] (outside North America).
(the addition before the i doesnt count; it just separates the real and imaginary parts notationally). But it is sometimes faster to multiply via (a + ib)(c + id) = (ac bd) + i[(a + b)(c + d) ac bd] (5.4.2)
which has only three multiplications (ac, bd, (a + b)(c + d)), plus two additions and three subtractions. The total operations count is higher by two, but multiplication is a slow operation on some machines. While it is true that intermediate results in equations (5.4.1) and (5.4.2) can overow even when the nal result is representable, this happens only when the nal answer is on the edge of representability. Not so for the complex modulus, if you are misguided enough to compute it as |a + ib| = a2 + b 2 (bad!) (5.4.3)
whose intermediate result will overow if either a or b is as large as the square root of the largest representable number (e.g., 10 19 as compared to 10 38 ). The right way to do the calculation is |a + ib| = |a| 1 + (b/a)2 |b| 1 + (a/b)2 |a| |b| |a| < |b| (5.4.4)
Complex division should use a similar trick to prevent avoidable overows, underow, or loss of precision, [a + b(d/c)] + i[b a(d/c)] a + ib c + d(d/c) = [ a ( c/d ) + b] + i[b(c/d) a] c + id c(c/d) + d |c| |d| (5.4.5) |c| < |d|
Of course you should calculate repeated subexpressions, like c/d or d/c, only once. Complex square root is even more complicated, since we must both guard intermediate results, and also enforce a chosen branch cut (here taken to be the negative real axis). To take the square root of c + id, rst compute 0 |c| w |d| c=d=0 1+ 1+ 2 (d/c)2 |c| |d| |c| < |d| (5.4.6)
|c/d| +
1 + (c/d)2 2
Chapter 5.
Evaluation of Functions
c + id =
0 w +i
|d| + iw 2w |d| iw 2w
nEn+1 (x) = ex xEn (x) cos n = 2 cos cos(n 1) cos(n 2) sin n = 2 cos sin(n 1) sin(n 2)
where the rst three functions are Legendre polynomials, Bessel functions of the rst kind, and exponential integrals, respectively. (For notation see [1].) These relations are useful for extending computational methods from two successive values of n to other values, either larger or smaller. Equations (5.5.4) and (5.5.5) motivate us to say a few words about trigonometric functions. If your programs running time is dominated by evaluating trigonometric functions, you are probably doing something wrong. Trig functions whose arguments form a linear sequence = 0 + n , n = 0, 1, 2, . . . , are efciently calculated by the following recurrence, cos( + ) = cos [ cos + sin ] sin( + ) = sin [ sin cos ] (5.5.6)