This is Info file calc.info, produced by Makeinfo-1.55 from the input file calc.texinfo. This file documents Calc, the GNU Emacs calculator. Copyright (C) 1990, 1991 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the section entitled "GNU General Public License" is included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that the section entitled "GNU General Public License" may be included in a translation approved by the author instead of in the original English. File: calc.info, Node: List Answer 7, Next: List Answer 8, Prev: List Answer 6, Up: Answers to Exercises List Tutorial Exercise 7 ------------------------ Here's one solution. First, compute the triangular list from the previous exercise and type `1 -' to subtract one from all the elements. 1: [ [0], [0, 1], [0, 1, 2], ... 1 - The numbers down the lefthand edge of the list we desire are called the "triangular numbers" (now you know why!). The `n'th triangular number is the sum of the integers from 1 to `n', and can be computed directly by the formula `n * (n+1) / 2'. 2: [ [0], [0, 1], ... ] 2: [ [0], [0, 1], ... ] 1: [0, 1, 2, 3, 4, 5] 1: [0, 1, 3, 6, 10, 15] . . v x 6 RET 1 - V M ' $ ($+1)/2 RET Adding this list to the above list of lists produces the desired result: 1: [ [0], [1, 2], [3, 4, 5], [6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19, 20] ] . V M + If we did not know the formula for triangular numbers, we could have computed them using a `V U +' command. We could also have gotten them the hard way by mapping a reduction across the original triangular list. 2: [ [0], [0, 1], ... ] 2: [ [0], [0, 1], ... ] 1: [ [0], [0, 1], ... ] 1: [0, 1, 3, 6, 10, 15] . . RET V M V R + (This means "map a `V R +' command across the vector," and since each element of the main vector is itself a small vector, `V R +' computes the sum of its elements.) File: calc.info, Node: List Answer 8, Next: List Answer 9, Prev: List Answer 7, Up: Answers to Exercises List Tutorial Exercise 8 ------------------------ The first step is to build a list of values of `x'. 1: [1, 2, 3, ..., 21] 1: [0, 1, 2, ..., 20] 1: [0, 0.25, 0.5, ..., 5] . . . v x 21 RET 1 - 4 / s 1 Next, we compute the Bessel function values. 1: [0., 0.124, 0.242, ..., -0.328] . V M ' besJ(1,$) RET (Another way to do this would be `1 TAB V M f j'.) A way to isolate the maximum value is to compute the maximum using `V R X', then compare all the Bessel values with that maximum. 2: [0., 0.124, 0.242, ... ] 1: [0, 0, 0, ... ] 2: [0, 0, 0, ... ] 1: 0.5801562 . 1: 1 . . RET V R X V M a = RET V R + DEL It's a good idea to verify, as in the last step above, that only one value is equal to the maximum. (After all, a plot of `sin(x)' might have many points all equal to the maximum value, 1.) The vector we have now has a single 1 in the position that indicates the maximum value of `x'. Now it is a simple matter to convert this back into the corresponding value itself. 2: [0, 0, 0, ... ] 1: [0, 0., 0., ... ] 1: 1.75 1: [0, 0.25, 0.5, ... ] . . . r 1 V M * V R + If `a =' had produced more than one `1' value, this method would have given the sum of all maximum `x' values; not very useful! In this case we could have used `v m' (`calc-mask-vector') instead. This command deletes all elements of a "data" vector that correspond to zeros in a "mask" vector, leaving us with, in this example, a vector of maximum `x' values. The built-in `a X' command maximizes a function using more efficient methods. Just for illustration, let's use `a X' to maximize `besJ(1,x)' over this same interval. 2: besJ(1, x) 1: [1.84115, 0.581865] 1: [0 .. 5] . . ' besJ(1,x), [0..5] RET a X x RET The output from `a X' is a vector containing the value of `x' that maximizes the function, and the function's value at that maximum. As you can see, our simple search got quite close to the right answer. File: calc.info, Node: List Answer 9, Next: List Answer 10, Prev: List Answer 8, Up: Answers to Exercises List Tutorial Exercise 9 ------------------------ Step one is to convert our integer into vector notation. 1: 25129925999 3: 25129925999 . 2: 10 1: [11, 10, 9, ..., 1, 0] . 25129925999 RET 10 RET 12 RET v x 12 RET - 1: 25129925999 1: [0, 2, 25, 251, 2512, ... ] 2: [100000000000, ... ] . . V M ^ s 1 V M \ (Recall, the `\' command computes an integer quotient.) 1: [0, 2, 5, 1, 2, 9, 9, 2, 5, 9, 9, 9] . 10 V M % s 2 Next we must increment this number. This involves adding one to the last digit, plus handling carries. There is a carry to the left out of a digit if that digit is a nine and all the digits to the right of it are nines. 1: [0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1] 1: [1, 1, 1, 0, 0, 1, ... ] . . 9 V M a = v v 1: [1, 1, 1, 0, 0, 0, ... ] 1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] . . V U * v v 1 | Accumulating `*' across a vector of ones and zeros will preserve only the initial run of ones. These are the carries into all digits except the rightmost digit. Concatenating a one on the right takes care of aligning the carries properly, and also adding one to the rightmost digit. 2: [0, 0, 0, 0, ... ] 1: [0, 0, 2, 5, 1, 2, 9, 9, 2, 6, 0, 0, 0] 1: [0, 0, 2, 5, ... ] . . 0 r 2 | V M + 10 V M % Here we have concatenated 0 to the *left* of the original number; this takes care of shifting the carries by one with respect to the digits that generated them. Finally, we must convert this list back into an integer. 3: [0, 0, 2, 5, ... ] 2: [0, 0, 2, 5, ... ] 2: 1000000000000 1: [1000000000000, 100000000000, ... ] 1: [100000000000, ... ] . . 10 RET 12 ^ r 1 | 1: [0, 0, 20000000000, 5000000000, ... ] 1: 25129926000 . . V M * V R + Another way to do this final step would be to reduce the formula `10 $$ + $' across the vector of digits. 1: [0, 0, 2, 5, ... ] 1: 25129926000 . . V R ' 10 $$ + $ RET File: calc.info, Node: List Answer 10, Next: List Answer 11, Prev: List Answer 9, Up: Answers to Exercises List Tutorial Exercise 10 ------------------------- For the list `[a, b, c, d]', the result is `((a = b) = c) = d', which will compare `a' and `b' to produce a 1 or 0, which is then compared with `c' to produce another 1 or 0, which is then compared with `d'. This is not at all what Joe wanted. Here's a more correct method: 1: [7, 7, 7, 8, 7] 2: [7, 7, 7, 8, 7] . 1: 7 . ' [7,7,7,8,7] RET RET v r 1 RET 1: [1, 1, 1, 0, 1] 1: 0 . . V M a = V R * File: calc.info, Node: List Answer 11, Next: List Answer 12, Prev: List Answer 10, Up: Answers to Exercises List Tutorial Exercise 11 ------------------------- The circle of unit radius consists of those points `(x,y)' for which `x^2 + y^2 < 1'. We start by generating a vector of `x^2' and a vector of `y^2'. We can make this go a bit faster by using the `v .' and `t .' commands. 2: [2., 2., ..., 2.] 2: [2., 2., ..., 2.] 1: [2., 2., ..., 2.] 1: [1.16, 1.98, ..., 0.81] . . v . t . 2. v b 100 RET RET V M k r 2: [2., 2., ..., 2.] 1: [0.026, 0.96, ..., 0.036] 1: [0.026, 0.96, ..., 0.036] 2: [0.53, 0.81, ..., 0.094] . . 1 - 2 V M ^ TAB V M k r 1 - 2 V M ^ Now we sum the `x^2' and `y^2' values, compare with 1 to get a vector of 1/0 truth values, then sum the truth values. 1: [0.56, 1.78, ..., 0.13] 1: [1, 0, ..., 1] 1: 84 . . . + 1 V M a < V R + The ratio `84/100' should approximate the ratio `pi/4'. 1: 0.84 1: 3.36 2: 3.36 1: 1.0695 . . 1: 3.14159 . 100 / 4 * P / Our estimate, 3.36, is off by about 7%. We could get a better estimate by taking more points (say, 1000), but it's clear that this method is not very efficient! (Naturally, since this example uses random numbers your own answer will be slightly different from the one shown here!) If you typed `v .' and `t .' before, type them again to return to full-sized display of vectors. File: calc.info, Node: List Answer 12, Next: List Answer 13, Prev: List Answer 11, Up: Answers to Exercises List Tutorial Exercise 12 ------------------------- This problem can be made a lot easier by taking advantage of some symmetries. First of all, after some thought it's clear that the `y' axis can be ignored altogether. Just pick a random `x' component for one end of the match, pick a random direction `theta', and see if `x' and `x + cos(theta)' (which is the `x' coordinate of the other endpoint) cross a line. The lines are at integer coordinates, so this happens when the two numbers surround an integer. Since the two endpoints are equivalent, we may as well choose the leftmost of the two endpoints as `x'. Then `theta' is an angle pointing to the right, in the range -90 to 90 degrees. (We could use radians, but it would feel like cheating to refer to `pi/2' radians while trying to estimate `pi'!) In fact, since the field of lines is infinite we can choose the coordinates 0 and 1 for the lines on either side of the leftmost endpoint. The rightmost endpoint will be between 0 and 1 if the match does not cross a line, or between 1 and 2 if it does. So: Pick random `x' and `theta', compute `x + cos(theta)', and count how many of the results are greater than one. Simple! We can make this go a bit faster by using the `v .' and `t .' commands. 1: [0.52, 0.71, ..., 0.72] 2: [0.52, 0.71, ..., 0.72] . 1: [78.4, 64.5, ..., -42.9] . v . t . 1. v b 100 RET V M k r 180. v b 100 RET V M k r 90 - (The next step may be slow, depending on the speed of your computer.) 2: [0.52, 0.71, ..., 0.72] 1: [0.72, 1.14, ..., 1.45] 1: [0.20, 0.43, ..., 0.73] . . m d V M C + 1: [0, 1, ..., 1] 1: 0.64 1: 3.125 . . . 1 V M a > V R + 100 / 2 TAB / Let's try the third method, too. We'll use random integers up to one million. The `k r' command with an integer argument picks a random integer. 2: [1000000, 1000000, ..., 1000000] 2: [78489, 527587, ..., 814975] 1: [1000000, 1000000, ..., 1000000] 1: [324014, 358783, ..., 955450] . . 1000000 v b 100 RET RET V M k r TAB V M k r 1: [1, 1, ..., 25] 1: [1, 1, ..., 0] 1: 0.56 . . . V M k g 1 V M a = V R + 100 / 1: 10.714 1: 3.273 . . 6 TAB / Q For a proof of this property of the GCD function, see section 4.5.2, exercise 10, of Knuth's *Art of Computer Programming*, volume II. If you typed `v .' and `t .' before, type them again to return to full-sized display of vectors. File: calc.info, Node: List Answer 13, Next: List Answer 14, Prev: List Answer 12, Up: Answers to Exercises List Tutorial Exercise 13 ------------------------- First, we put the string on the stack as a vector of ASCII codes. 1: [84, 101, 115, ..., 51] . "Testing, 1, 2, 3 RET Note that the `"' key, like `$', initiates algebraic entry so there was no need to type an apostrophe. Also, Calc didn't mind that we omitted the closing `"'. (The same goes for all closing delimiters like `)' and `]' at the end of a formula. We'll show two different approaches here. In the first, we note that if the input vector is `[a, b, c, d]', then the hash code is `3 (3 (3a + b) + c) + d = 27a + 9b + 3c + d'. In other words, it's a sum of descending powers of three times the ASCII codes. 2: [84, 101, 115, ..., 51] 2: [84, 101, 115, ..., 51] 1: 16 1: [15, 14, 13, ..., 0] . . RET v l v x 16 RET - 2: [84, 101, 115, ..., 51] 1: 1960915098 1: 121 1: [14348907, ..., 1] . . . 3 TAB V M ^ * 511 % Once again, `*' elegantly summarizes most of the computation. But there's an even more elegant approach: Reduce the formula `3 $$ + $' across the vector. Recall that this represents a function of two arguments that computes its first argument times three plus its second argument. 1: [84, 101, 115, ..., 51] 1: 1960915098 . . "Testing, 1, 2, 3 RET V R ' 3$$+$ RET If you did the decimal arithmetic exercise, this will be familiar. Basically, we're turning a base-3 vector of digits into an integer, except that our "digits" are much larger than real digits. Instead of typing `511 %' again to reduce the result, we can be cleverer still and notice that rather than computing a huge integer and taking the modulo at the end, we can take the modulo at each step without affecting the result. While this means there are more arithmetic operations, the numbers we operate on remain small so the operations are faster. 1: [84, 101, 115, ..., 51] 1: 121 . . "Testing, 1, 2, 3 RET V R ' (3$$+$)%511 RET Why does this work? Think about a two-step computation: `3 (3a + b) + c'. Taking a result modulo 511 basically means subtracting off enough 511's to put the result in the desired range. So the result when we take the modulo after every step is, 3 (3 a + b - 511 m) + c - 511 n for some suitable integers `m' and `n'. Expanding out by the distributive law yields 9 a + 3 b + c - 511*3 m - 511 n The `m' term in the latter formula is redundant because any contribution it makes could just as easily be made by the `n' term. So we can take it out to get an equivalent formula with `n' = 3m + n', 9 a + 3 b + c - 511 n' which is just the formula for taking the modulo only at the end of the calculation. Therefore the two methods are essentially the same. Later in the tutorial we will encounter "modulo forms", which basically automate the idea of reducing every intermediate result modulo some value M. File: calc.info, Node: List Answer 14, Next: Types Answer 1, Prev: List Answer 13, Up: Answers to Exercises List Tutorial Exercise 14 ------------------------- We want to use `H V U' to nest a function which adds a random step to an `(x,y)' coordinate. The function is a bit long, but otherwise the problem is quite straightforward. 2: [0, 0] 1: [ [ 0, 0 ] 1: 50 [ 0.4288, -0.1695 ] . [ -0.4787, -0.9027 ] ... [0,0] 50 H V U ' <# + [random(2.0)-1, random(2.0)-1]> RET Just as the text recommended, we used `< >' nameless function notation to keep the two `random' calls from being evaluated before nesting even begins. We now have a vector of `[x, y]' sub-vectors, which by Calc's rules acts like a matrix. We can transpose this matrix and unpack to get a pair of vectors, `x' and `y', suitable for graphing. 2: [ 0, 0.4288, -0.4787, ... ] 1: [ 0, -0.1696, -0.9027, ... ] . v t v u g f Incidentally, because the `x' and `y' are completely independent in this case, we could have done two separate commands to create our `x' and `y' vectors of numbers directly. To make a random walk of unit steps, we note that `sincos' of a random direction exactly gives us an `[x, y]' step of unit length; in fact, the new nesting function is even briefer, though we might want to lower the precision a bit for it. 2: [0, 0] 1: [ [ 0, 0 ] 1: 50 [ 0.1318, 0.9912 ] . [ -0.5965, 0.3061 ] ... [0,0] 50 m d p 6 RET H V U ' <# + sincos(random(360.0))> RET Another `v t v u g f' sequence will graph this new random walk. An interesting twist on these random walk functions would be to use complex numbers instead of 2-vectors to represent points on the plane. In the first example, we'd use something like `random + random*(0,1)', and in the second we could use polar complex numbers with random phase angles. (This exercise was first suggested in this form by Randal Schwartz.) File: calc.info, Node: Types Answer 1, Next: Types Answer 2, Prev: List Answer 14, Up: Answers to Exercises Types Tutorial Exercise 1 ------------------------- If the number is the square root of `pi' times a rational number, then its square, divided by `pi', should be a rational number. 1: 1.26508260337 1: 0.509433962268 1: 2486645810:4881193627 . . . 2 ^ P / c F Technically speaking this is a rational number, but not one that is likely to have arisen in the original problem. More likely, it just happens to be the fraction which most closely represents some irrational number to within 12 digits. But perhaps our result was not quite exact. Let's reduce the precision slightly and try again: 1: 0.509433962268 1: 27:53 . . U p 10 RET c F Aha! It's unlikely that an irrational number would equal a fraction this simple to within ten digits, so our original number was probably `sqrt(27 pi / 53)'. Notice that we didn't need to re-round the number when we reduced the precision. Remember, arithmetic operations always round their inputs to the current precision before they begin. File: calc.info, Node: Types Answer 2, Next: Types Answer 3, Prev: Types Answer 1, Up: Answers to Exercises Types Tutorial Exercise 2 ------------------------- `inf / inf = nan'. Perhaps `1' is the "obvious" answer. But if `17 inf = inf', then `17 inf / inf = inf / inf = 17', too. `exp(inf) = inf'. It's tempting to say that the exponential of infinity must be "bigger" than "regular" infinity, but as far as Calc is concerned all infinities are as just as big. In other words, as `x' goes to infinity, `e^x' also goes to infinity, but the fact the `e^x' grows much faster than `x' is not relevant here. `exp(-inf) = 0'. Here we have a finite answer even though the input is infinite. `sqrt(-inf) = (0, 1) inf'. Remember that `(0, 1)' represents the imaginary number `i'. Here's a derivation: `sqrt(-inf) = sqrt((-1) * inf) = sqrt(-1) * sqrt(inf)'. The first part is, by definition, `i'; the second is `inf' because, once again, all infinities are the same size. `sqrt(uinf) = uinf'. In fact, we do know something about the direction because `sqrt' is defined to return a value in the right half of the complex plane. But Calc has no notation for this, so it settles for the conservative answer `uinf'. `abs(uinf) = inf'. No matter which direction `x' points, `abs(x)' always points along the positive real axis. `ln(0) = -inf'. Here we have an infinite answer to a finite input. As in the `1 / 0' case, Calc will only use infinities here if you have turned on "infinite" mode. Otherwise, it will treat `ln(0)' as an error. File: calc.info, Node: Types Answer 3, Next: Types Answer 4, Prev: Types Answer 2, Up: Answers to Exercises Types Tutorial Exercise 3 ------------------------- We can make `inf - inf' be any real number we like, say, `a', just by claiming that we added `a' to the first infinity but not to the second. This is just as true for complex values of `a', so `nan' can stand for a complex number. (And, similarly, `uinf' can stand for an infinity that points in any direction in the complex plane, such as `(0, 1) inf'). In fact, we can multiply the first `inf' by two. Surely `2 inf - inf = inf', but also `2 inf - inf = inf - inf = nan'. So `nan' can even stand for infinity. Obviously it's just as easy to make it stand for minus infinity as for plus infinity. The moral of this story is that "infinity" is a slippery fish indeed, and Calc tries to handle it by having a very simple model for infinities (only the direction counts, not the "size"); but Calc is careful to write `nan' any time this simple model is unable to tell what the true answer is. File: calc.info, Node: Types Answer 4, Next: Types Answer 5, Prev: Types Answer 3, Up: Answers to Exercises Types Tutorial Exercise 4 ------------------------- 2: 0@ 47' 26" 1: 0@ 2' 47.411765" 1: 17 . . 0@ 47' 26" RET 17 / The average song length is two minutes and 47.4 seconds. 2: 0@ 2' 47.411765" 1: 0@ 3' 7.411765" 1: 0@ 53' 6.000005" 1: 0@ 0' 20" . . . 20" + 17 * The album would be 53 minutes and 6 seconds long. File: calc.info, Node: Types Answer 5, Next: Types Answer 6, Prev: Types Answer 4, Up: Answers to Exercises Types Tutorial Exercise 5 ------------------------- Let's suppose it's January 14, 1991. The easiest thing to do is to keep trying 13ths of months until Calc reports a Friday. We can do this by manually entering dates, or by using `t I': 1: 1: 1: . . . ' <2/13> RET DEL ' <3/13> RET t I (Calc assumes the current year if you don't say otherwise.) This is getting tedious--we can keep advancing the date by typing `t I' over and over again, but let's automate the job by using vector mapping. The `t I' command actually takes a second "how-many-months" argument, which defaults to one. This argument is exactly what we want to map over: 2: 1: [, , 1: [1, 2, 3, 4, 5, 6] , , . , ] . v x 6 RET V M t I Et voila, September 13, 1991 is a Friday. 1: 242 . ' - RET And the answer to our original question: 242 days to go. File: calc.info, Node: Types Answer 6, Next: Types Answer 7, Prev: Types Answer 5, Up: Answers to Exercises Types Tutorial Exercise 6 ------------------------- The full rule for leap years is that they occur in every year divisible by four, except that they don't occur in years divisible by 100, except that they *do* in years divisible by 400. We could work out the answer by carefully counting the years divisible by four and the exceptions, but there is a much simpler way that works even if we don't know the leap year rule. Let's assume the present year is 1991. Years have 365 days, except that leap years (whenever they occur) have 366 days. So let's count the number of days between now and then, and compare that to the number of years times 365. The number of extra days we find must be equal to the number of leap years there were. 1: 2: 1: 2925593 . 1: . . ' RET ' RET - 3: 2925593 2: 2925593 2: 2925593 1: 1943 2: 10001 1: 8010 1: 2923650 . 1: 1991 . . . 10001 RET 1991 - 365 * - There will be 1943 leap years before the year 10001. (Assuming, of course, that the algorithm for computing leap years remains unchanged for that long. *Note Date Forms::, for some interesting background information in that regard.) File: calc.info, Node: Types Answer 7, Next: Types Answer 8, Prev: Types Answer 6, Up: Answers to Exercises Types Tutorial Exercise 7 ------------------------- The relative errors must be converted to absolute errors so that `+/-' notation may be used. 1: 1. 2: 1. . 1: 0.2 . 20 RET .05 * 4 RET .05 * Now we simply chug through the formula. 1: 19.7392088022 1: 394.78 +/- 19.739 1: 6316.5 +/- 706.21 . . . 2 P 2 ^ * 20 p 1 * 4 p .2 RET 2 ^ * It turns out the `v u' command will unpack an error form as well as a vector. This saves us some retyping of numbers. 3: 6316.5 +/- 706.21 2: 6316.5 +/- 706.21 2: 6316.5 1: 0.1118 1: 706.21 . . RET v u TAB / Thus the volume is 6316 cubic centimeters, within about 11 percent. File: calc.info, Node: Types Answer 8, Next: Types Answer 9, Prev: Types Answer 7, Up: Answers to Exercises Types Tutorial Exercise 8 ------------------------- The first answer is pretty simple: `1 / (0 .. 10) = (0.1 .. inf)'. Since a number in the interval `(0 .. 10)' can get arbitrarily close to zero, its reciprocal can get arbitrarily large, so the answer is an interval that effectively means, "any number greater than 0.1" but with no upper bound. The second answer, similarly, is `1 / (-10 .. 0) = (-inf .. -0.1)'. Calc normally treats division by zero as an error, so that the formula `1 / 0' is left unsimplified. Our third problem, `1 / [0 .. 10]', also (potentially) divides by zero because zero is now a member of the interval. So Calc leaves this one unevaluated, too. If you turn on "infinite" mode by pressing `m i', you will instead get the answer `[0.1 .. inf]', which includes infinity as a possible value. The fourth calculation, `1 / (-10 .. 10)', has the same problem. Zero is buried inside the interval, but it's still a possible value. It's not hard to see that the actual result of `1 / (-10 .. 10)' will be either greater than 0.1, or less than -0.1. Thus the interval goes from minus infinity to plus infinity, with a "hole" in it from -0.1 to 0.1. Calc doesn't have any way to represent this, so it just reports `[-inf .. inf]' as the answer. It may be disappointing to hear "the answer lies somewhere between minus infinity and plus infinity, inclusive," but that's the best that interval arithmetic can do in this case. File: calc.info, Node: Types Answer 9, Next: Types Answer 10, Prev: Types Answer 8, Up: Answers to Exercises Types Tutorial Exercise 9 ------------------------- 1: [-3 .. 3] 2: [-3 .. 3] 2: [0 .. 9] . 1: [0 .. 9] 1: [-9 .. 9] . . [ 3 n .. 3 ] RET 2 ^ TAB RET * In the first case the result says, "if a number is between -3 and 3, its square is between 0 and 9." The second case says, "the product of two numbers each between -3 and 3 is between -9 and 9." An interval form is not a number; it is a symbol that can stand for many different numbers. Two identical-looking interval forms can stand for different numbers. The same issue arises when you try to square an error form. File: calc.info, Node: Types Answer 10, Next: Types Answer 11, Prev: Types Answer 9, Up: Answers to Exercises Types Tutorial Exercise 10 -------------------------- Testing the first number, we might arbitrarily choose 17 for `x'. 1: 17 mod 811749613 2: 17 mod 811749613 1: 533694123 mod 811749613 . 811749612 . . 17 M 811749613 RET 811749612 ^ Since 533694123 is (considerably) different from 1, the number 811749613 must not be prime. It's awkward to type the number in twice as we did above. There are various ways to avoid this, and algebraic entry is one. In fact, using a vector mapping operation we can perform several tests at once. Let's use this method to test the second number. 2: [17, 42, 100000] 1: [1 mod 15485863, 1 mod ... ] 1: 15485863 . . [17 42 100000] 15485863 RET V M ' ($$ mod $)^($-1) RET The result is three ones (modulo `n'), so it's very probable that 15485863 is prime. (In fact, this number is the millionth prime.) Note that the functions `($$^($-1)) mod $' or `$$^($-1) % $' would have been hopelessly inefficient, since they would have calculated the power using full integer arithmetic. Calc has a `k p' command that does primality testing. For small numbers it does an exact test; for large numbers it uses a variant of the Fermat test we used here. You can use `k p' repeatedly to prove that a large integer is prime with any desired probability. File: calc.info, Node: Types Answer 11, Next: Types Answer 12, Prev: Types Answer 10, Up: Answers to Exercises Types Tutorial Exercise 11 -------------------------- There are several ways to insert a calculated number into an HMS form. One way to convert a number of seconds to an HMS form is simply to multiply the number by an HMS form representing one second: 1: 31415926.5359 2: 31415926.5359 1: 8726@ 38' 46.5359" . 1: 0@ 0' 1" . . P 1e7 * 0@ 0' 1" * 2: 8726@ 38' 46.5359" 1: 6@ 6' 2.5359" mod 24@ 0' 0" 1: 15@ 27' 16" mod 24@ 0' 0" . . x time RET + It will be just after six in the morning. The algebraic `hms' function can also be used to build an HMS form: 1: hms(0, 0, 10000000. pi) 1: 8726@ 38' 46.5359" . . ' hms(0, 0, 1e7 pi) RET = The `=' key is necessary to evaluate the symbol `pi' to the actual number 3.14159... File: calc.info, Node: Types Answer 12, Next: Types Answer 13, Prev: Types Answer 11, Up: Answers to Exercises Types Tutorial Exercise 12 -------------------------- As we recall, there are 17 songs of about 2 minutes and 47 seconds each. 2: 0@ 2' 47" 1: [0@ 3' 7" .. 0@ 3' 47"] 1: [0@ 0' 20" .. 0@ 1' 0"] . . [ 0@ 20" .. 0@ 1' ] + 1: [0@ 52' 59." .. 1@ 4' 19."] . 17 * No matter how long it is, the album will fit nicely on one CD. File: calc.info, Node: Types Answer 13, Next: Types Answer 14, Prev: Types Answer 12, Up: Answers to Exercises Types Tutorial Exercise 13 -------------------------- Type `' 1 yr RET u c s RET'. The answer is 31557600 seconds. File: calc.info, Node: Types Answer 14, Next: Types Answer 15, Prev: Types Answer 13, Up: Answers to Exercises Types Tutorial Exercise 14 -------------------------- How long will it take for a signal to get from one end of the computer to the other? 1: m / c 1: 3.3356 ns . . ' 1 m / c RET u c ns RET (Recall, `c' is a "unit" corresponding to the speed of light.) 1: 3.3356 ns 1: 0.81356 ns / ns 1: 0.81356 2: 4.1 ns . . . ' 4.1 ns RET / u s Thus a signal could take up to 81 percent of a clock cycle just to go from one place to another inside the computer, assuming the signal could actually attain the full speed of light. Pretty tight! File: calc.info, Node: Types Answer 15, Next: Algebra Answer 1, Prev: Types Answer 14, Up: Answers to Exercises Types Tutorial Exercise 15 -------------------------- The speed limit is 55 miles per hour on most highways. We want to find the ratio of Sam's speed to the US speed limit. 1: 55 mph 2: 55 mph 3: 11 hr mph / yd . 1: 5 yd / hr . . ' 55 mph RET ' 5 yd/hr RET / The `u s' command cancels out these units to get a plain number. Now we take the logarithm base two to find the final answer, assuming that each successive pill doubles his speed. 1: 19360. 2: 19360. 1: 14.24 . 1: 2 . . u s 2 B Thus Sam can take up to 14 pills without a worry. File: calc.info, Node: Algebra Answer 1, Next: Algebra Answer 2, Prev: Types Answer 15, Up: Answers to Exercises Algebra Tutorial Exercise 1 --------------------------- The result `sqrt(x)^2' is simplified back to `x' by the Calculator, but `sqrt(x^2)' is not. (Consider what happens if `x = -4'.) If `x' is real, this formula could be simplified to `abs(x)', but for general complex arguments even that is not safe. (*Note Declarations::, for a way to tell Calc that `x' is known to be real.) File: calc.info, Node: Algebra Answer 2, Next: Algebra Answer 3, Prev: Algebra Answer 1, Up: Answers to Exercises Algebra Tutorial Exercise 2 --------------------------- Suppose our roots are `[a, b, c]'. We want a polynomial which is zero when `x' is any of these values. The trivial polynomial `x-a' is zero when `x=a', so the product `(x-a)(x-b)(x-c)' will do the job. We can use `a c x' to write this in a more familiar form. 1: 34 x - 24 x^3 1: [1.19023, -1.19023, 0] . . r 2 a P x RET 1: [x - 1.19023, x + 1.19023, x] 1: (x - 1.19023) (x + 1.19023) x . . V M ' x-$ RET V R * 1: x^3 - 1.41666 x 1: 34 x - 24 x^3 . . a c x RET 24 n * a x Sure enough, our answer (multiplied by a suitable constant) is the same as the original polynomial. File: calc.info, Node: Algebra Answer 3, Next: Algebra Answer 4, Prev: Algebra Answer 2, Up: Answers to Exercises Algebra Tutorial Exercise 3 --------------------------- 1: x sin(pi x) 1: (sin(pi x) - pi x cos(pi x)) / pi^2 . . ' x sin(pi x) RET m r a i x RET 1: [y, 1] 2: (sin(pi x) - pi x cos(pi x)) / pi^2 . ' [y,1] RET TAB 1: [(sin(pi y) - pi y cos(pi y)) / pi^2, (sin(pi) - pi cos(pi)) / pi^2] . V M $ RET 1: (sin(pi y) - pi y cos(pi y)) / pi^2 + (pi cos(pi) - sin(pi)) / pi^2 . V R - 1: (sin(3.14159 y) - 3.14159 y cos(3.14159 y)) / 9.8696 - 0.3183 . = 1: [0., -0.95493, 0.63662, -1.5915, 1.2732] . v x 5 RET TAB V M $ RET File: calc.info, Node: Algebra Answer 4, Next: Rewrites Answer 1, Prev: Algebra Answer 3, Up: Answers to Exercises Algebra Tutorial Exercise 4 --------------------------- The hard part is that `V R +' is no longer sufficient to add up all the contributions from the slices, since the slices have varying coefficients. So first we must come up with a vector of these coefficients. Here's one way: 2: -1 2: 3 1: [4, 2, ..., 4] 1: [1, 2, ..., 9] 1: [-1, 1, ..., -1] . . . 1 n v x 9 RET V M ^ 3 TAB - 1: [4, 2, ..., 4, 1] 1: [1, 4, 2, ..., 4, 1] . . 1 | 1 TAB | Now we compute the function values. Note that for this method we need eleven values, including both endpoints of the desired interval. 2: [1, 4, 2, ..., 4, 1] 1: [1, 1.1, 1.2, ... , 1.8, 1.9, 2.] . 11 RET 1 RET .1 RET C-u v x 2: [1, 4, 2, ..., 4, 1] 1: [0., 0.084941, 0.16993, ... ] . ' sin(x) ln(x) RET m r p 5 RET V M $ RET Once again this calls for `V M * V R +'; a simple `*' does the same thing. 1: 11.22 1: 1.122 1: 0.374 . . . * .1 * 3 / Wow! That's even better than the result from the Taylor series method. File: calc.info, Node: Rewrites Answer 1, Next: Rewrites Answer 2, Prev: Algebra Answer 4, Up: Answers to Exercises Rewrites Tutorial Exercise 1 ---------------------------- We'll use Big mode to make the formulas more readable. ___ 2 + V 2 1: (2 + sqrt(2)) / (1 + sqrt(2)) 1: -------- . ___ 1 + V 2 . ' (2+sqrt(2)) / (1+sqrt(2)) RET d B Multiplying by the conjugate helps because `(a+b) (a-b) = a^2 - b^2'. ___ ___ 1: (2 + V 2 ) (V 2 - 1) . a r a/(b+c) := a*(b-c) / (b^2-c^2) RET ___ ___ 1: 2 + V 2 - 2 1: V 2 . . a r a*(b+c) := a*b + a*c a s (We could have used `a x' instead of a rewrite rule for the second step.) The multiply-by-conjugate rule turns out to be useful in many different circumstances, such as when the denominator involves sines and cosines or the imaginary constant `i'. File: calc.info, Node: Rewrites Answer 2, Next: Rewrites Answer 3, Prev: Rewrites Answer 1, Up: Answers to Exercises Rewrites Tutorial Exercise 2 ---------------------------- Here is the rule set: [ fib(n) := fib(n, 1, 1) :: integer(n) :: n >= 1, fib(1, x, y) := x, fib(n, x, y) := fib(n-1, y, x+y) ] The first rule turns a one-argument `fib' that people like to write into a three-argument `fib' that makes computation easier. The second rule converts back from three-argument form once the computation is done. The third rule does the computation itself. It basically says that if `x' and `y' are two consecutive Fibonacci numbers, then `y' and `x+y' are the next (overlapping) pair of Fibonacci numbers. Notice that because the number `n' was "validated" by the conditions on the first rule, there is no need to put conditions on the other rules because the rule set would never get that far unless the input were valid. That further speeds computation, since no extra conditions need to be checked at every step. Actually, a user with a nasty sense of humor could enter a bad three-argument `fib' call directly, say, `fib(0, 1, 1)', which would get the rules into an infinite loop. One thing that would help keep this from happening by accident would be to use something like `ZzFib' instead of `fib' as the name of the three-argument function. File: calc.info, Node: Rewrites Answer 3, Next: Rewrites Answer 4, Prev: Rewrites Answer 2, Up: Answers to Exercises Rewrites Tutorial Exercise 3 ---------------------------- He got an infinite loop. First, Calc did as expected and rewrote `2 + 3 x' to `f(2, 3, x)'. Then it looked for ways to apply the rule again, and found that `f(2, 3, x)' looks like `a + b x' with `a = 0' and `b = 1', so it rewrote to `f(0, 1, f(2, 3, x))'. It then wrapped another `f(0, 1, ...)' around that, and so on, ad infinitum. Joe should have used `M-1 a r' to make sure the rule applied only once. (Actually, even the first step didn't work as he expected. What Calc really gives for `M-1 a r' in this situation is `f(3 x, 1, 2)', treating 2 as the "variable," and `3 x' as a constant being added to it. While this may seem odd, it's just as valid a solution as the "obvious" one. One way to fix this would be to add the condition `:: variable(x)' to the rule, to make sure the thing that matches `x' is indeed a variable, or to change `x' to `quote(x)' on the lefthand side, so that the rule matches the actual variable `x' rather than letting `x' stand for something else.) File: calc.info, Node: Rewrites Answer 4, Next: Rewrites Answer 5, Prev: Rewrites Answer 3, Up: Answers to Exercises Rewrites Tutorial Exercise 4 ---------------------------- Here is a suitable set of rules to solve the first part of the problem: [ seq(n, c) := seq(n/2, c+1) :: n%2 = 0, seq(n, c) := seq(3n+1, c+1) :: n%2 = 1 :: n > 1 ] Given the initial formula `seq(6, 0)', application of these rules produces the following sequence of formulas: seq( 3, 1) seq(10, 2) seq( 5, 3) seq(16, 4) seq( 8, 5) seq( 4, 6) seq( 2, 7) seq( 1, 8) whereupon neither of the rules match, and rewriting stops. We can pretty this up a bit with a couple more rules: [ seq(n) := seq(n, 0), seq(1, c) := c, ... ] Now, given `seq(6)' as the starting configuration, we get 8 as the result. The change to return a vector is quite simple: [ seq(n) := seq(n, []) :: integer(n) :: n > 0, seq(1, v) := v | 1, seq(n, v) := seq(n/2, v | n) :: n%2 = 0, seq(n, v) := seq(3n+1, v | n) :: n%2 = 1 ] Given `seq(6)', the result is `[6, 3, 10, 5, 16, 8, 4, 2, 1]'. Notice that the `n > 1' guard is no longer necessary on the last rule since the `n = 1' case is now detected by another rule. But a guard has been added to the initial rule to make sure the initial value is suitable before the computation begins. While still a good idea, this guard is not as vitally important as it was for the `fib' function, since calling, say, `seq(x, [])' will not get into an infinite loop. Calc will not be able to prove the symbol `x' is either even or odd, so none of the rules will apply and the rewrites will stop right away. File: calc.info, Node: Rewrites Answer 5, Next: Rewrites Answer 6, Prev: Rewrites Answer 4, Up: Answers to Exercises Rewrites Tutorial Exercise 5 ---------------------------- If `x' is the sum `a + b', then `nterms(x)' must be `nterms(a)' plus `nterms(b)'. If `x' is not a sum, then `nterms(x)' = 1. [ nterms(a + b) := nterms(a) + nterms(b), nterms(x) := 1 ] Here we have taken advantage of the fact that earlier rules always match before later rules; `nterms(x)' will only be tried if we already know that `x' is not a sum. File: calc.info, Node: Rewrites Answer 6, Next: Rewrites Answer 7, Prev: Rewrites Answer 5, Up: Answers to Exercises Rewrites Tutorial Exercise 6 ---------------------------- Just put the rule `0^0 := 1' into `EvalRules'. For example, before making this definition we have: 2: [-2, -1, 0, 1, 2] 1: [1, 1, 0^0, 1, 1] 1: 0 . . v x 5 RET 3 - 0 V M ^ But then: 2: [-2, -1, 0, 1, 2] 1: [1, 1, 1, 1, 1] 1: 0 . . U ' 0^0:=1 RET s t EvalRules RET V M ^ Perhaps more surprisingly, this rule still works with infinite mode turned on. Calc tries `EvalRules' before any built-in rules for a function. This allows you to override the default behavior of any Calc feature: Even though Calc now wants to evaluate `0^0' to `nan', your rule gets there first and evaluates it to 1 instead. Just for kicks, try adding the rule `2+3 := 6' to `EvalRules'. What happens? (Be sure to remove this rule afterward, or you might get a nasty surprise when you use Calc to balance your checkbook!) File: calc.info, Node: Rewrites Answer 7, Next: Programming Answer 1, Prev: Rewrites Answer 6, Up: Answers to Exercises Rewrites Tutorial Exercise 7 ---------------------------- Here is a rule set that will do the job: [ a*(b + c) := a*b + a*c, opt(a) O(x^n) + opt(b) O(x^m) := O(x^n) :: n <= m :: constant(a) :: constant(b), opt(a) O(x^n) + opt(b) x^m := O(x^n) :: n <= m :: constant(a) :: constant(b), a O(x^n) := O(x^n) :: constant(a), x^opt(m) O(x^n) := O(x^(n+m)), O(x^n) O(x^m) := O(x^(n+m)) ] If we really want the `+' and `*' keys to operate naturally on power series, we should put these rules in `EvalRules'. For testing purposes, it is better to put them in a different variable, say, `O', first. The first rule just expands products of sums so that the rest of the rules can assume they have an expanded-out polynomial to work with. Note that this rule does not mention `O' at all, so it will apply to any product-of-sum it encounters--this rule may surprise you if you put it into `EvalRules'! In the second rule, the sum of two O's is changed to the smaller O. The optional constant coefficients are there mostly so that `O(x^2) - O(x^3)' and `O(x^3) - O(x^2)' are handled as well as `O(x^2) + O(x^3)'. The third rule absorbs higher powers of `x' into O's. The fourth rule says that a constant times a negligible quantity is still negligible. (This rule will also match `O(x^3) / 4', with `a = 1/4'.) The fifth rule rewrites, for example, `x^2 O(x^3)' to `O(x^5)'. (It is easy to see that if one of these forms is negligible, the other is, too.) Notice the `x^opt(m)' to pick up terms like `x O(x^3)'. Optional powers will match `x' as `x^1' but not 1 as `x^0'. This turns out to be exactly what we want here. The sixth rule is the corresponding rule for products of two O's. Another way to solve this problem would be to create a new "data type" that represents truncated power series. We might represent these as function calls `series(COEFS, X)' where COEFS is a vector of coefficients for `x^0', `x^1', `x^2', and so on. Rules would exist for sums and products of such `series' objects, and as an optional convenience could also know how to combine a `series' object with a normal polynomial. (With this, and with a rule that rewrites `O(x^n)' to the equivalent `series' form, you could still enter power series in exactly the same notation as before.) Operations on such objects would probably be more efficient, although the objects would be a bit harder to read. Some other symbolic math programs provide a power series data type similar to this. Mathematica, for example, has an object that looks like `PowerSeries[X, X0, COEFS, NMIN, NMAX, DEN]', where X0 is the point about which the power series is taken (we've been assuming this was always zero), and NMIN, NMAX, and DEN allow pseudo-power-series with fractional or negative powers. Also, the `PowerSeries' objects have a special display format that makes them look like `2 x^2 + O(x^4)' when they are printed out. (*Note Compositions::, for a way to do this in Calc, although for something as involved as this it would probably be better to write the formatting routine in Lisp.) File: calc.info, Node: Programming Answer 1, Next: Programming Answer 2, Prev: Rewrites Answer 7, Up: Answers to Exercises Programming Tutorial Exercise 1 ------------------------------- Just enter the formula `ninteg(sin(t)/t, t, 0, x)', type `Z F', and answer the questions. Since this formula contains two variables, the default argument list will be `(t x)'. We want to change this to `(x)' since `t' is really a dummy variable to be used within `ninteg'. The exact keystrokes are `Z F s Si RET RET C-b C-b DEL DEL RET y'. (The `C-b C-b DEL DEL' are what fix the argument list.)