Sie sind auf Seite 1von 17
9 Numbers Number-crunching is one of Common Lisp's strengths, It has a rich set of ‘numeric types, and its features for manipulating numbers compare favorably ‘with any language, 9.1 Types Common Lisp provides four distinct types of numbers: integers, floating- point numbers, ratios, and complex numbers. Most of the functions described in this chapter work on numbers of any type. A few, explicitly noted, accept all but complex numbers. ‘An integers written asa string of digits: 2001. A floating-point number can be writen asa string of digits containing a decimal point, 253.72, or in scientific notation, 2.537262. A ratiois written asa fraction of integers: 2/3. ‘And the complex number atbi is written as #c(a b), where a and b are any two real numbers ofthe same type. ‘The predicates integerp, floatp, and complexp retum true for num- bers of the corresponding types. Figure 9.1 shows the hierarchy of numeric ‘ype. Here are some genera rules of thumb for determining what kind of number a computation will ture: 1, If a numeric function receives one or more floating-point numbers as arguments, the return value will be a floating-point number (or a complex number with floating-point components). So (+ 1.0 2) evaluates to 3.0, and (+ #¢(O 1.0) 2) evaluates to &<(2-0 1.0) 143 144 NUMBERS rational ignum 7 farum — bt veal short single-foat umber fat oubie-oat | long-lost complex * Figure 9.1; Numeric types. 2. Ratios that divide evenly will be converted into integers. So (/ 10 2) will return 6, 3. Complex numbers whose imaginary part would be zero will be con- verted into reals. So (+ #e(1 =1) #c(2 1)) evaluates to 3. Rules 2 and 3 apply to arguments as soon as they are read, so > (list (ratiop 2/2) (complexp #e(1 0))) (QUIL NTL) 9.2. Conversion and Extraction Lisp provides functions for converting, and extracting components of, the four kinds of numbers. The function float converts any real number to a floating-point number: > (mapear #float *(1 2/3 .8)) (1.0 0.666667 0.5) Reducing numbers to integers is not necessarily conversion, because it can {involve some loss of information, The function truncate returns the integer component of any real number: > (truncate 1.3) 1 0. 29999995 92 ‘CONVERSION AND EXTRACTION 145 ‘The second return value is the original argument minus the first return value. (The difference of .0000000 is due to the inherent inexactitude of floating point computation.) ‘The functions f oor, ceiling, and round also derive integers from their arguments, Using floor, which returns the greatest integer less than or equal to its argument, and ceiling, which returns the least integer greater than or equal to its argument, we can generalize mirror? (page 46) to recognize all palindromes: (dofun palindrone? (x) Get ((aid (/ Cength x) 2))) (equal (subseq x 0 (floor mid)) Goverse (subseq x (coiling mid)))))) Like truncate, floor and coiling also retum as a second value the difference between the argument and the first return value: > (fleor 1.5) 1 0.8 In fact, we could think of truncate as being defined: (defun our-truncate (n) Gt O20) (floor 2) (ceiling 0))) ‘The function round retums the nearest integer to its argument. When the argument is equidistant from two integers, Common Lisp, like many ‘programming languages, does not round up. Instead it rounds to the nearest even digit: > (mapear #?round *(-2.5 -1.5 1.5 2.6)) (2-222) In some numerical applications this is a good thing, because rounding errors tend to cancel one another out. However, if end-users are expecting your ‘program to round certain values up, you must provide for this yourself.' Like its cousins, round retums as its second value the difference between the argument and the first return value. ‘The function mod returns just the second value that floor would return; and rem returns just the second value that truncate would return, We used "When format rounds fr display, it doesnt even guarantee to round oan even or od digi. See page 125, 146 NUMBERS ‘mod on page 94 to determine if one number was divisible by another, and on page 127 to find the actual position of an element in a ring buffer. For reals, the function si gnum returns either 1, 0, or ~1, depending on whether its argument is postive, zero, or negative. The function abs retums the absolute value of its argument. Thus (# (abs x) (signum x) > (mapcar #?signum '(-2 -0.0 0.0 0 .5 3)) (-1 -0.0 0.00 1.0 1) In some implementations -0 .0 may exist in its own right, as above. Fune- tionally it makes litle difference whether it does or not, because in numeric code -0.0 behaves exactly like 0.0. Ratios and complex numbers are conceptually two-part structures. The functions nunerator and denominator return the corresponding compo- nents of a ratio or integer. (If the number is an integer, the former returns the number itself and the latter returns 1.) ‘The functions realpart and imagpart return the real and imaginary components of any number. (Ifthe ‘number isn’t complex, the former returns the number itself and the latter returns zer0.) The function random takes an integer or floating-point number. An expression of the form (random n) retums a number greater than or equal to zero and less than and of the same type as . 9.3 Comparison ‘The predicate = returns rue when its arguments are numerically equal—when the difference between them is zero. = 1 1.0) T > (eqi 1 1.0) NIL [is less strict than eq], which also requires its arguments to be of the same ‘ype. ‘The predicates for comparing numbers are < (less than) , <= (less than for equal), = (equal), >= (greater than or equal), > (greater than), and (Gifferent). All of them take one or more arguments. With one argument they all ret t. Forall except /=, a call with three or more arguments, (ew xyz) is equivalent to the conjunction of a binary operator applied to successive pairs of arguments: 94 ARITHMETIC 147 (and (<= w x) (Kx y) (= y 2)) Since /= returns true if no two of its arguments are =, the expression Usuxy2) is equivalent 0 (and (= w x) (ew x) Je v2) Us x9) Ue x2) Vey 2)) The specialized predicates zerop, plusp, andminusp take one argument and return true if it is =, >, and < zero, respectively. These functions do not, overlap. Although -0.0 (if an implementation uses it) is preceded by a negative sign, itis = to 0, > (list (minusp -0.0) (zerop -0.0)) uh 1) and therefore zerop, not minusp. ‘The predicates odap and evenp apply only to integers. The former is true only of odd integers, and the latter only of even ones. (Of the predicates described in this section, only to complex numbers. The functions max and min return, respectively, the maximum and mini- ‘mum of their arguments, Both require at least one: and zerop apply > (list (max 12.345) (min 123 4 5)) (61) If the arguments to either include floating-point numbers, the type of the result is implementation-dependent, 94° Arithmetic ‘The functions for addition and subtraction are + and -. Both can take any number of arguments, including none, in which case they return 0. An expression of the form (= n) retums ~n. An expression of the form xyz) is equivalent to Cex 148 NUMBERS There are also two functions 1+ and 1~, which return their argument plus 1 ‘and minus 1 respectively. The name 1~ isa bit misleading, because (1~ x) returns x — 1, not 1 —x. ‘The macros incf and decf increment and decrement their argument, respectively, An expression of the form (incf x n) is similar in effect 10 (sett x (+ x n)),and (decf x n) to (sett x (~ x n)), Inbothcases the second argument is optional and defaults o 1 ‘The function for multiplication is *. It takes any number of arguments ‘When given no arguments it returns 1, Otherwise it returns the product of its arguments. ‘The division function, /, expects atleast one argument. A call ofthe form (/ n) is equivalent to (/ 1 n), >U a) 4/3 while a call ofthe form xy 2) is equivalent 10 GUxpe Notice the similarity between ~ and / in this respect. When given two integers, / will return a ratio ifthe first is not 2 multiple of the second > (/ 365 12) 365/12 If what you're trying to do is find out how long an average month is, for ‘example, this may give the impression that the toplevel is playing games with ‘you. In such cases, what you really need is to call float on a ratio, not / on ‘wo integers: > (float 365/12) 30. 416866 9.5 Exponentiation ‘To find x" we call (expt x m), > (expt 2 5) 32 97 "TRIGONOMETRIC FUNCTIONS 149 and to find loggx we call (Log x n) > (og 32 2) 5.0 This will ordinarily return a floating-point number. To find e* there is a distinct function exp, > (exp 2) 7.389056 and to find a natural logarithm you can just use log, because the second. argument defaults to e > (og 7.389056) 2.0 ‘To find roots you can call expt with a ratio as the second argument, > (expt 27 1/3) 3.0 but for finding square roots the function sqrt should be faster: > (sqrt 4) 2.0 9.6 Trigonometric Functions ‘The constant pi is a floating-point representation of x. Its precision is {implementation-dependent. The functions sin, cos, and tan find the sine, ‘cosine, and tangent, respectively, of angles expressed in radians: > Get C(x (/ pi 4))) Gist (sin x) (cos x) (tan x))) (0.707106781186547540 0.707106781 186547640 1.040) These functions all take negative and complex arguments. ‘The functions asin, acos, and atan implement the inverse of sine, cosine, and tangent. For arguments between —1 and 1 inclusive, asin and cos return real numbers. Hyperbolic sine, cosine, and tangent are implemented by sinh, cosh, and ‘tanh, respectively. Their inverses are likewise asinh, acosh, and atanh, 150 NUMBERS 9.7 Representation ‘Common Lisp imposes no limit on the size of integers. Small integers fit in ‘one word of memory and are called fiznums. When a computation produces an integer too large to fit in one memory word, Lisp switches to a representation (a bignum) that uses multiple words of memory. So the effective limit on the size of an integer is imposed by physical memory, not by the language. ‘The constants nost-positive-fixnun and most-negative-fixnum indicate the largest magnitudes an implementation can represent without hhaving to use bignums. In many implementations they > (values most-positive-fixnun most-negative-fixnun) 536870911 536870912 ‘The predicate typep takes an argument and a type name and returns true if the argument is ofthe specified type. So, > (typep 1 *fixnum) 7 > (typep (1+ most-positive-fixnum) 'bignum) T ‘The limits on the values of floating-point numbers are implementation- dependent, Common Lisp provides for up to four types of floating-point num- bers: short-float, single-float, double-float, and long-float. Implementations are not required to use distinct formats for all four types (and few do). ‘The general idea is that a short float is supposed to fit in a single word, that single and double floats are supposed to provide the usual idea of single- and double-precision floating-point numbers, and that long floats can be something really big, if desired. But an implementation could perfectly well implement all four the same way. You can specify what format you want a floating-point number to be by substituting the letters s, £, 4, or 1 for the e when a number is represented in scientific notation. (You can use uppercase 100, and this is a good idea for long floats, because 1 looks so much like 1.) So to make the largest representation of 1 .0 you would write 1L0. Sixteen global constants mark the limits of each format in a given imple- mentation, Their names are of the form m=s-f, whete mis nost or least, is positive or negative, and fis one of the four types of float.” Floating-point underflow and overflow are signalled as errorsby Common Lisp: > (+ most~positive-long-float 10) Error: floating-point-overflow. 98 EXAMPLE: RAY-TRACING 151 9.8 Example: Ray-Tracing ‘As an example of a mostly numerical application, this section shows how to write a ray-tracer. Ray-tracing is the rendering algorithm deluxe: it yields the most realistic images, but takes the most time. ‘To generate a 3D image, we need to define atleast four things: an eye, one or more light sources, a simulated world consisting of one or more surfaces, and a plane (the image plane) that serves as a window onto this world, The image we generate is the projection of the world onto a region of the image plane. ‘What makes ray-tracing unusual is the way we find this projection: we go pixel-by-pixel along the image plane, tracing the ight back into the simulated. world. This approach brings three main advantages: it makes it easy to get real-world optical effects like transparency, reflected light, and cast shadows, itallows us to define the simulated world directly in terms of whatever geo- metric objects we want, instead of having to construct them out of polygons; and itis straightforward to implement. Figure 9.2 contains some math utilities we are going to need in our ray- tracer. The first, 6q, just retums the square of its argument. The next, nag, returns the length of a vector given its x, y, and z components. This function is used in the nexttwo. We use itinunit-vector, which returns three values representing the components of a unit vector with the same direction as the vector whose components are x, y, and 2: > (gultiple-value-call #’mag (unit-vector 23 12 47)) 1.0 ‘And we use mag in distance, which retums the distance between two points in 3-space. (Defining the point structure to have a :conc-name of nil ‘means that the access functions forthe fields will have the same names asthe fields: x instead of pointx, for example.) Finally, minroot takes three reals a, b, and c, and retums the smallest real x for which ar? + bx +c = 0. When a is nonzero, the roots of this, equation are yielded by the familiar formula ~bi Vea aae Ya Figure 9.3 contains code defining a minimal ray-tracer. It generates black and white images illuminated by a single light source, atthe same position as the eye, (The results thus tend to look like flash photographs.) ‘The surface structure will be used to represent the objects in the simu- lated world. More precisely, it will be included in the structures defined to represent specific kinds of objects, like spheres. The surface structure itself ‘contains only a single field: a color ranging from 0 (black) to 1 (white). 152 NUMBERS @ @ xx) (detun mag (x y 2) (sqrt ( (sq x) (sq y) (sq z)))) Getun unit-vector (x y 2) (let ((d (mag x y z))) (values (/x a) (/ y 4) (/ z @)))) (defetruct (point (:conc-nane ni1)) xyz) (detun distance (p1 p2) (mag (~ (x pt) @ p2)) © & PL) Gy p2)) ( G pt) ( p2)))) (Gefun minroot (a bc) (it (zerop a) Ue) db) (let (aise (- (sq b) (#4 a c)))) (unless (minusp disc) Get ((discrt (sqrt disc))) (min (/ ( (- b) discrt) (* 2 a)) UG G ») discrt) ( 2 a)))))))) Figure 9.2: Math utilities. ‘The image plane will be the plane defined by the x- and y-axes. The eye will be on the 2-axis, 200 units from the origin. So to be visible through the image plane, the surfaces that get inserted into *world (initially ni1) will have to have negative 2 coordinates, Figure 9.4 illustrates a ray passing. through @ point on the image plane and hitting a sphere. ‘The function tracer takes a pathname and writes an image to the cor- responding file. Image files will be writen in a simple ascit format called PGM. By default, images will be 100% 100. The header in our POM files will consist of the tag P2, followed by integers indicating the breadth (100) and ‘height (100) of the image in pixels, and the highest possible value (255). The remainder of the file will consist of 10,000 integers between 0 (black) and 255 (white), representing 100 horizontal stripes of 100 pixels. 98 EXAMPLE: RAY-TRACING 153 Getstruct surface color) (detparaneter *world* nil) (detconstant eye (make-point :x 0 :y 0 :z 200)) (@otun tracer (pathnane optional (zes 1)) (with-open-file (p pathname :direction :output) (format p "P2 ~A ~A 255" (* res 100) (# res 100)) et (Cine (/ res))) (ao ((y ~50 (+ y inc))) ((< ( 60 y) inc)) (do ((x -50 (+ x inc))) ({< (- 50 x) inc)) (print (color-at x y) p)))))) (defun color-at (x y) (qultiple-value~bind (xr yr zr) (unit-vector (~ x (x y & eye)) (- 0 (z eye))) (round (* (sendray eye xr yr 2r) 258)))) (efun sendray (pt xr yr zr) (qultiple-value-bind (s int) (first-hit pt xr yr zr) Gifts (+ Gambert s int xr yr 2x) (surface-color s)) 0») (defun first-hit (pt xr yr zr) let (surface hit dist) (@olist (s *vorla*) Get ((h Gintersect s pt xr yr zr))) (when b (let ((4 (distance b pt))) (hen (or (mull dist) (< 4 dist)) (sett surface s hit h dist 4)))))) (values surface hit))) (defun lambert (s int xr yr zr) (qultiple-value-bind (xn yn zn) (normal s int) (max 0 ( (« xr xn) (m yr yn) (# zr zn))))) Figure 9.3: Ray-tracing 154 NUMBERS, a point of iow image plan Figure 9.4: Ray-tracing. ‘The resolution of the image can be adjusted by giving an explicit res. If res is 2, for example, then the same image will be rendered with 200% 200 pixels. “The image isa 100100 square on the image plane. Each pixel represents the amount of light that passes through the image plane a that point on the way to the eye. To find the amount of light at each pixel, tracer calls color-at. This function finds the vector from the eye to that point, then calls sendray to trace the course of this vector back into the simulated world; ‘sendray will return an intensity value between O and 1, which i then scaled toan integer between 0 and 255 for display. “To determine the intensity ofa ray, sendray has to find the object that it was reflected from. To do this it ells #irst-bit, which considers all the surfaces in sword, and returns the surface (if any) that the ray hit fis. If the ray doesnt hit anything, sendray just returns the background color, which by convention is 0 (black). Ifthe Fay does hit something, we have to find out the amount of light shining on the surface atthe point where the ray hits it Lamberts law says thatthe intensity of light reflected by a point on @ surface is proportional tothe dot-product of the unit normal vector N at that point (the vector of length 1 that is perpendicular to the surface there), and the unit vector from the point tothe light sour i=NL If the light is shining right at the point, N and L will be coincident, and the dot-product will be 1, the maximum value. Ifthe surface is tured 90° to the light at that point, then V and L willbe perpendicular, and their dot-product will be 0. Ifthe light is behind the surface, the dot product will be negative, In our program, we are assuming thatthe light source is atthe eye, so Lambert, which uses this rule to find the illumination at some point on a surface, returns the dot-product of the normal with the ray we were tracing 98 EXAMPLE: RAY-TRACING 155 In sendray this value is multiplied by the color of the surface (a dark surface 4s dark even when wel-illaminated) to determine the overall intensity at that point. For simplicity, we will have only one kind of object in our simulated world, spheres. Figure 9.5 contains the code involving spheres. The sphere structure includes aurface, so a sphere will have a color as well as a center and radius. Calling def sphere adds @ new one tothe world. ‘The function intersect considers the type of surface involved and calls the corresponding intersect function. At the moment there is only one, sphere-intersect, but intersect is written so that it can easily be ex- tended to deal with other kinds of objects. How do we find the intersection of a ray with a sphere? The ray is represented as a point p = (x0. Yo. 2), and a unit vector v= (xp, 27). Every point on the ray can be expressed as p + nv, for some n—thatis, a8 (iy + xr. + myn % + ney). Where the ray hits the sphere, the distance from that point tothe center (xc, ye. Ze) will be equal t the sphere’s radius r. So atthe intersection the following equation will hold: r= eotne ‘This yields =P + (io + my, ~ I) + (eo ter — zo? an? +in+e=0 where a=u+y+d b= (x0 — Ket + (Yo = Ye)¥e + (20 ~ Ze)zr) 6 (a0 ~ te)? + (9 ~ Ye)? + (20 ze)? 7 To find the imersection we just find the roots of this quadratic equation. Tt ‘might have zer0, one, or two real roots. No roots means thatthe ray misses the sphere; one root means that it intersects the sphere at one point (a grazing hit: and two roots means that it intersects the sphere at two points (in one side and out the other). In the later ease, we want the smaller ofthe two roots; increases as the ray travels away from the eye, so the first ht isthe smaller n. Hence the call tominroct. If there isa root, sphere-intersect. returns the point representing (x9 + mr, 3p + mr 20 + mer). ‘The other two functions in Figure 93, normal and sphere-normal, are analogous to intersect and sphere-intersect. Finding the normal to a sphere is easy-—it's just the vector from the point tothe center ofthe sphere. Figure 9.6 shows how we would generate an image; ray-test. defines 238 spheres (not all of which will be visible) and then generates an image 156 NUMBERS, (detstruct (sphere (:include surface)) radius center) (aefun defsphere (x y z Fc) et ((s (make-sphere radius center (make-point :x x :y y :z z) reelor c))) (push # #xorlds) 8) (defun intersect (s pt xr yr zr) (funcall (typecase 8 (sphere #’sphere-intersect)) s pt xr yr zr)) (detun sphere-intersect (s pt xr yr 2x) Get+ ((c (ophere-center 5)) Se eee rte CIT y G2 CG pt) & eo) x) G@ © G pe) Go) we) G © @ pv (0) 2») @ Gq © G pt) Ge) (sq © G pt) G 2?) (eq (- (@ pt) @ 0) ( (eq (ophere-radius s))))))) Gta (aake-point :x (+ (x pt) (¢ n xz) ry @ Gy pt) (en yr) 2 (4 (@ pt) (* n 2r)))))) (@etun normal (s pt) (funcall (typecase s (sphere #’sphere-nornal)) 5 pt)) (detun sphere-normal (s pt) (et ((c (sphere-center s))) (unit-vector (~ (x c) (x pt)) © G ©) G pt) © @e) @ped)))) Figure 9.5: Spheres. 98 EXAMPLE: RAY-TRACING 157 [ aetun ray-test (boptionsl (res D) | Gaett svortae ni1) | Gotsprere 0 -300 -1200 200 .8) | (@etsphere -80 -150 -1200 200 .7) | (defsphere 70 -100 -1200 200 .9) (do (Cx -2 (1+ x))) (© x 2)) (do ((z 2 (1+ 2))) (@27)) | (defsphere (+* x 200) 300 (* z -400) 40 .75))) (tracer (nake-pathnane :nane "spheres pgn") res)) Figure 9.6: Using the ray-tracer. Figure 9.7; Ray-traced image, file called "spheres .pgn", Figure 9.7 shows the resulting image, generated with a res of 10, A real ray-tracer could generate much more sophisticated images, because it would consider more than just the contribution of a single light source to a 158 NUMBERS point on a surface. There might be multiple light sources, each of different intensities. They would not ordinarily be tthe eye, in which case the program ‘would have to check to see whether the vector to a light source intersected another surface, which would then be casting its shadow onto the frst, Puting. the light source atthe eye saves us from having to consider this complication, because we can’t see any of the points that are in shadow. ‘A real ray-tracer would also follow the ray beyond the frst surface it hit, adding in some amount of light reflected by other surfaces. It would do color, of course, and would also be able to model surfaces that were transparent or shiny. But the basic algorithm would remain much as shown in Figure 9.3, ‘and many of the refinements would just involve recursive uses of the same ingredients, ‘real ray-tracer would probably also be highly optimized. The program given here is written for brevity, and is not even optimized as a Lisp pro- ‘gram, let alone as a ray-tracer. Merely adding type and inline declarations (Section 13.3) could make it more than twice as fast. Summary 1. Common Lisp provides integers, ratios, floating-point numbers, and complex numbers. 2. Numbers can be simplified and converted, and their components can be extracted, 3, Predicates for comparing numbers take any number of arguments, and ‘compare successive pairs—except /=, which compares all pairs. 4. Common Lisp provides roughly the numerical functions you might see ‘on a low-end scientific calculator. The same functions generally apply to numbers of several types. 5. Fixnums are integers small enough to fitin one word. They are quietly but expensively converted to bignums when necessary. Common Lisp provides for up to four types of floating-point number. The limits of ‘each representation are implementation-dependent constants. 6. A ray-tracer generates an image by tracing the light that makes each pixel back into a simulated world. Exercises 1. Define a function that takes a list of reals and returns true iff they are in nondecreasing order. 98 EXERCISES 159 Define a function that takes an integer number of cents and returns four values showing how to make that number out of 25-, 10-,5- and I-cent pieces, using the smallest total number of coins, ‘A faraway planet is inhabited by two kinds of beings, wigglies and ‘wobblies. Wigglies and wobblies are equally good at singing. Every year there isa great competition to chooses the ten best singers. Here are the results for the past ten years: Year JT] 3 [9 [10 rwiectes 163] reqs] wonauies | 41 5 stats] Write a program to simulate such a contest. Do your results suggest that the committee is, in fact, choosing the ten best singers each year? Define a function that takes 8 reals representing the endpoints of two segments in 2-space, and returns either nil if the segments do not intersect, or two values representing the x- and y-coordinates of the intersection if they do, ‘Suppose f is a function of one (real) argument, and that min and max are nonzero reals with different signs such that # has a root (returns zero) for one argument i such that min < i < max. Define a function that takes four arguments, £, min, max, and epeilon, and returns an approximation of # accurate to within plus or minus epson. Horner's method is a tick for evaluating polynomials efficiently. To find ax'+ x +-ex+d youevaluate x(x(ax+b)+c)+d. Define a function that takes one oF more arguments—the value of x followed by n reals representing the coeficients of an (n ~ 1)th-degree polynomial—and calculates the value ofthe polynomial by Horner's method, How many bits would you estimate your implementation uses to rep- resent fixnums? How many distinct types of float does your implementation provide?

Das könnte Ihnen auch gefallen