c1-2 (779456), страница 4
Текст из файла (страница 4)
All recent C compilers have this ability, but it is not inthe original K&R C definition. If you are missing it, you will have to rewrite thefunctions in complex.c, making them pass and return pointers to variables of typefcomplex instead of the variables themselves. Likewise, you will need to modifythe recipes that use the functions.Several other routines (e.g., the Fourier transforms four1 and fourn) docomplex arithmetic “by hand,” that is, they carry around real and imaginary parts asfloat variables. This results in more efficient code than would be obtained by usingthe functions in complex.c.
But the code is even less readable. There is simply noideal solution to the complex arithmetic problem in C.Implicit Conversion of Float to DoubleIn traditional (K&R) C, float variables are automatically converted to doublebefore any operation is attempted, including both arithmetic operations and passingas arguments to functions. All arithmetic is then done in double precision. If afloat variable receives the result of such an arithmetic operation, the high precisionSample 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 servercomputer, is strictly prohibited. To order Numerical Recipes books,diskettes, or CDROMsvisit website http://www.nr.com or call 1-800-872-7423 (North America only),or send email to trade@cup.cam.ac.uk (outside North America).fcomplex Cmul(fcomplex a, fcomplex b)Returns the complex product of two complex numbers.1.2 Some C Conventions for Scientific Computing25A Few WrinklesWe like to keep code compact, avoiding unnecessary spaces unless they addimmediate clarity. We usually don’t put space around the assignment operator “=”.Through a quirk of history, however, some C compilers recognize the (nonexistent)operator “=-” as being equivalent to the subtractive assignment operator “-=”, and“=*” as being the same as the multiplicative assignment operator “*=”.
That is whyyou will see us write y= -10.0; or y=(-10.0);, and y= *a; or y=(*a);.We have the same viewpoint regarding unnecessary parentheses. You can’t write(or read) C effectively unless you memorize its operator precedence and associativityrules. Please study the accompanying table while you brush your teeth every night.We never use the register storage class specifier. Good optimizing compilersare quite sophisticated in making their own decisions about what to keep in registers,and the best choices are sometimes rather counter-intuitive.Different compilers use different methods of distinguishing between definingand referencing declarations of the same external name in several files.
We followthe most common scheme, which is also the ANSI standard. The storage classextern is explicitly included on all referencing top-level declarations. The storageclass is omitted from the single defining declaration for each external variable. Wehave commented these declarations, so that if your compiler uses a different schemeyou can change the code. The various schemes are discussed in §4.8 of [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 servercomputer, is strictly prohibited. To order Numerical Recipes books,diskettes, or CDROMsvisit website http://www.nr.com or call 1-800-872-7423 (North America only),or send email to trade@cup.cam.ac.uk (outside North America).is immediately thrown away. A corollary of these rules is that all the real-numberstandard C library functions are of type double and compute to double precision.The justification for these conversion rules is, “well, there’s nothing wrong witha little extra precision,” and “this way the libraries need only one version of eachfunction.” One does not need much experience in scientific computing to recognizethat the implicit conversion rules are, in fact, sheer madness! In effect, they make itimpossible to write efficient numerical programs.
One of the cultural barriers thatseparates computer scientists from “regular” scientists and engineers is a differingpoint of view on whether a 30% or 50% loss of speed is worth worrying about. Inmany real-time or state-of-the-art scientific applications, such a loss is catastrophic.The practical scientist is trying to solve tomorrow’s problem with yesterday’scomputer; the computer scientist, we think, often has it the other way around.The ANSI C standard happily does not allow implicit conversion for arithmeticoperations, but it does require it for function arguments, unless the function is fullyprototyped by an ANSI declaration as described earlier in this section.
That isanother reason for our being rigorous about using the ANSI prototype mechanism,and a good reason for you to use an ANSI-compatible compiler.Some older C compilers do provide an optional compilation mode in whichthe implicit conversion of float to double is suppressed. Use this if you can.In this book, when we write float, we mean float; when we write double,we mean double, i.e., there is a good algorithmic reason for having higherprecision. Our routines all can tolerate the traditional implicit conversion rules,but they are more efficient without them.
Of course, if your application actuallyrequires double precision, you can change our declarations from float to doublewithout difficulty. (The brute force approach is to add a preprocessor statement#define float double !)26Chapter 1.PreliminariesOperator Precedence and Associativity Rules in Cleft-to-rightlogical notbitwise complementunary minusincrementdecrementaddress ofcontents ofcast to typesize in bytesright-to-left*/%multiplydivideremainderleft-to-right+-addsubtractleft-to-right<<>>bitwise left shiftbitwise right shiftleft-to-right<><=>=arithmetic less thanarithmetic greater thanarithmetic less than or equal toarithmetic greater than or equal toleft-to-right==!=arithmetic equalarithmetic not equalleft-to-right&bitwise andleft-to-right^bitwise exclusive orleft-to-right|bitwise orleft-to-right&&logical andleft-to-right||logical orleft-to-rightconditional expressionright-to-left!~++-&*(type)sizeof?:=assignment operatoralso += -= *= /= %=<<= >>= &= ^= |=,sequential expressionright-to-leftleft-to-rightWe have already alluded to the problem of computing small integer powers ofnumbers, most notably the square and cube.
The omission of this operation from Cis perhaps the language’s most galling insult to the scientific programmer. All goodFORTRAN compilers recognize expressions like (A+B)**4 and produce in-line code,in this case with only one add and two multiplies. It is typical for constant integerpowers up to 12 to be thus recognized.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 servercomputer, is strictly prohibited. To order Numerical Recipes books,diskettes, or CDROMsvisit website http://www.nr.com or call 1-800-872-7423 (North America only),or send email to trade@cup.cam.ac.uk (outside North America).function callarray elementstructure or union memberpointer reference to structure()[].->1.2 Some C Conventions for Scientific Computing27In C, the mere problem of squaring is hard enough! Some people “macro-ize”the operation as#define SQR(a) ((a)*(a))static float sqrarg;#define SQR(a) (sqrarg=(a),sqrarg*sqrarg)The global variable sqrarg now has (and needs to keep) scope over the wholemodule, which is a little dangerous. Also, one needs a completely different macro tosquare expressions of type int. More seriously, this macro can fail if there are twoSQR operations in a single expression.
Since in C the order of evaluation of pieces ofthe expression is at the compiler’s discretion, the value of sqrarg in one evaluationof SQR can be that from the other evaluation in the same expression, producingnonsensical results. When we need a guaranteed-correct SQR macro, we use thefollowing, which exploits the guaranteed complete evaluation of subexpressions ina conditional expression:static float sqrarg;#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)A collection of macros for other simple operations is included in the file nrutil.h(see Appendix B) and used by many of our programs.
Here are the synopses:SQR(a)DSQR(a)FMAX(a,b)FMIN(a,b)DMAX(a,b)DMIN(a,b)IMAX(a,b)IMIN(a,b)LMAX(a,b)LMIN(a,b)SIGN(a,b)Square a float value.Square a double value.Maximum of two float values.Minimum of two float values.Maximum of two double values.Minimum of two double values.Maximum of two int values.Minimum of two int values.Maximum of two long values.Minimum of two long values.Magnitude of a times sign of b.Scientific programming in C may someday become a bed of roses; for now,watch out for the thorns!CITED REFERENCES AND FURTHER READING:Harbison, S.P., and Steele, G.L., Jr. 1991, C: A Reference Manual, 3rd ed. (Englewood Cliffs,NJ: Prentice-Hall). [1]AT&T Bell Laboratories 1985, The C Programmer’s Handbook (Englewood Cliffs, NJ: PrenticeHall).Kernighan, B., and Ritchie, D.