Dear DDJ,
I just read Pitts Jarvis's article, "Implementing Cordic Algorithms" (October 1990), which was brought to my attention by a friend who knew I was looking for such an algorithm. Unfortunately, that was a year ago. I did solve my problem, however, using this very same algorithm. I found the article very easy to understand and it certainly made the algorithm a lot clearer to me than it had been. I would like to add a couple of comments, if I may.
I had actually found these algorithms through Knuth's Fundamental Algorithms, specifically, exercise 28 in section 1.2.2 (and its answer, of course), which is concerned with performing exponentiation using only shifts, adds, and subtracts. The note at the end of the answer to the exercise says that there are similar algorithms for trig functions and gives references. Somewhere in the paper trail of references I read that the algorithm actually dates back to Briggs, 300 years ago. My friend told me that Briggs actually computed some of the original log tables. As I understand it, the logarithm algorithm may have developed into the trig algorithm by way of Euler's formula (which relates the two in the field of complex numbers).
Also, Pitts suggested these algorithms might be useful for graphics (which was my application) but I don't believe you indicated that the circular routines are extremely well suited for conversions between polar and rectangular coordinates. For example, I believe if you put r * K into the circular routine, you will get r * cos(a) and r * sin(a). And in the inverse routine, you unavoidably get sqrt(x * x = y * y)/K. In other words, these routines unavoidably do coordinate conversion. This, when I saw it, reminded me of HP calculators, one of which you say uses these algorithms.
I had also noticed (although I would not recommend them) that Taylor's series for the sine or cosine of a particular number requires all the same multiplications. My conclusion was that it would be nice if there were coordinate conversion routines in software libraries and available from floating point processors because they are often what is needed, and there is probably a lot of waste in computing sine and cosine independently. Of course, these (CORDIC) functions would require an intrinsic multiply or divide by K. Now I see that Intel '87s use this algorithm, and while simultaneous sine and cosine are available, software libraries (that I know of) don't make it available for high-level languages. So how about it? Will we see polar and rectangular coordinate conversion routines in standard libraries?
Also, the units or scale of r, x, and y need only be consistent; the algorithm is independent of this. The units or scale of the angle need only match the atan table, which theoretically could be a parameter of the function.
Anyway, yours was a very nice article, but where were you when I needed you?
Lawrence Leinweber
Cleveland Heights, Ohio
Pitts responds: Knuth attributes exercise 28 in section 1.2.2 (a method for exponentiation using only shift and add) to Richard Feynman, the Nobel prize winning physicist. Chapter 22 of The Feynman Lectures on Physics describes the method Henri Briggs used in 1620 to calculate the original table of logarithms. This chapter, entitled "Algebra," in the space of ten pages relates the trigonometric functions, logarithms, exponentials, complex numbers, e, and pi using only the basic notions of integers and counting. It is fascinating reading to see how the consequences of a few simple definitions and some algebraic manipulation can lead to Euler's formula.
The CORDIC algorithms perform rectangular/polar conversions by their very nature; however, you have to scale r carefully in order to avoid overflow as the algorithm runs.
For general-purpose floating calculations, it's probably more efficient to perform polar/rectangular conversions by computing sine and cosine separately, using methods based on approximation theory. Most floating point libraries use this method. This class of algorithms is tabulated in Computer Approximations, by J. F. Hart, et al. The CORDIC algorithms are useful in more specialized circumstances.
Dear DDJ,
In the June 1991 Programmer's Bookshelf, Ray Duncan takes Ed Yourdon to task: "What Yourdon views as programming, you and I would consider the tedious paper-pushing of burned-out middle managers."
I am sorry to have to tell Ray that Yourdon's view is the standard in large organizations. Still the standard. A full generation after people started to notice that good programmers frequently make poor managers, few big companies -- none at all, actually, in my 22 years of experience -- have any proper career structure for people whose natural talent is for what Ray correctly calls "the creative labor of programming." The assumption everywhere is that after three or four years cutting code, you have paid your dues and are entitled to be rewarded with a real job: issuing memos, drafting proposals, and attending meetings, meetings, meetings.
As a matter of fact, there is some justice in the Yourdon view. Most of those people who did their three years coding were not much good at it (ask the people who have to maintain their code!) and lapsed gratefully into the Unit Manager slot. Like most human beings, they had no talent or passion for anything outside their private lives, and so were best employed in a job requiring no talent or passion. The true casualties are those of us who love making code and are good at it, yet want to arrive at middle age earning a respectable salary. We are the losers in a culture dominated by the idea, once confined to empires of the bureaucratic-despotic type, that the only worthwhile form of human activity is directing the work of others: to say to this one, "Come," and he cometh, to say to that one, "Go," and he goeth. The goal of all endeavor is the Mandarin's cap. Those of us who don't want to be Mandarins, but who would like to be properly rewarded for useful work done with loving attention, are thought of as eccentrics. Try turning down that promotion to Unit Manager: They look at you as if you'd asked for a transfer to the mail room.
Between the middle management drone and the nerd hacker who never takes his eyes from the screen (all you ever see of him is his ponytail), there is another breed: the true programmer/analyst. We dress for business, and we know business. Years of working with accountants, engineers, executives, field engineers, and warehouse managers have taught us how they think and what their needs are. We can figure out their requirements, then we can go back to our cubes and turn those requirements into fast, maintainable, waterproof code. Not total loners, we can play the noncom when necessary, taking on a couple of support programmers and guiding their work to good effect. We understand the need for CASE methods and can operate perfectly well within them (pace your correspondent Andy Bender, same issue), though we'll never be enthusiastic about "functional specifications," "dataflow diagrams," and all those other submanagerial exercises in applied boredom, eating into time that could be spent coding or fishing around in users' minds. We don't mind turning to a 4GL for the occasional emergency enhancement, but will never believe that this is real programming. ("Oracle is for people who don't like computers," a colleague commented to me recently. We all know what he means: It's for the three-year people.)
Sick of the Mandarin ethos of large companies, we've tried to go into business for ourselves as code producers, but found we had no skill at marketing. We end up as "consultants," resented by permanent staff, harassed by the IRS, cut off from the life of the companies we work at.
When programmers first started to appear in business organizations, they were regarded with fear and suspicion, the possessors of arcane knowledge: anarchic, disruptive elements in the stately world of business management. The paper-pushers saw early on that computers were a threat to their status. They acted to contain and neutralize that threat. Now the Yourdons have taken over, and Harmony has been restored. Programmers -- like engineers in a previous generation (why do you think everything's now made in Japan?) -- have been marginalized and demoralized. Andy Bender can talk as much as he likes about the "professionalization" of software engineering and the need for a "standard university curriculum;" but if he thinks graduates of that curriculum will ever have the status of MBAs, he's dreaming.
There are consolations, though. Programming may, as a Mandarin recently told me, be "nothing but a glorified clerical function," but we still have our skill and our passion. And, of course, we still have Dr. Dobb's.
John Derbyshire
London, England
Dear DDJ,
Victor J. Duvanenko's "Efficiently Raising Matrices to an Integer Power" (June 1991) showed me that the method I have been using for raising real numbers to integer powers can also be used for matrices. I call this the "Russian peasant method" for exponentiation. It is closely related to a method of that name for multiplication which only involves the simple operations of halving, doubling, and adding.
While this is an efficient method of raising a matrix to an integer power, it is not an efficient method of computing Fibonacci numbers, as was implied in the article. There is an exact equation for Fibonacci numbers due to Jacques Philippe Marie Binet, published in 1843:
F(n) = (bn - cn)/a where a = Sqrt (5) b = (1 + a)/2 = Golden Ratio, c = (1 - a)/2 = 1 - b = -1/b
Since the magnitude of cn/a is less than 1/2 for n >= 0, an efficient method of computing Fibonacci numbers is the evaluation of the equation:
F(n) = Round(bn/a).
In C this can be programmed as:
#include <math.h> fib = floor(0.5 + pow(b,n)/a);
A program based on this method runs 15 to 20 times faster than Victor's matrix method.
Harry J. Smith
Saratoga, California
Dear DDJ,
I read "Efficiently Raising Matrices to an Integer Power" with great interest. Mr. Duvanenko's points are very well considered and illustrated.
Although it is not the major point of the article, I would like to add another method to compute Fibonacci numbers as an illustration of a more general point. The point is that there are frequently direct analytic methods that yield closed-form solutions. In fact, the Golden Ratio is not just the ratio of F(n) and f(n - 1) as n approaches infinity, but can be expressed more accurately as the (sqrt(5) + 1)/2. Frequently, the Golden Ratio is referred to as the Golden Number and is expressed as a nonrepeating decimal with an approximate value of 0.6180339.
You may find it interesting to note that the GN has some other interesting properties. For example, (GN - 1) = (1/GN).
A source of the closed form comes from discrete difference equations. The following is a short form solution:
F(n) = F(n - 1) + F(n - 2) F(n - 2) + F(n - 1) + F(n) = 0
When the del operator is defined as del(Fn)) = F(n - 1), then the general solution is a(b)n. Using the quadratic formula on the characteristic equation:
del del + del - 1 = 0
yields a general solution of
f(n) = 1/sqrt(5) ((1 + sqrt(5))/2)n -f(n) = 1/sqrt(5) ((1 - sqrt(5))/2)n
Using the closed form solution implemented with static constants yields a solution that computes in fixed time. This approach can be used with a variety of other functions, as shown in Example 1.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
static double Invsqrt5;
static double Sqrt5plus;
static double Sqrt5minus;
double fiber(int n);
int main (void)
{
int f_num;8
char f_str[80];
Invsqrt5 = 1.0 / sqrt(5.0);
Sqrt5plus = (1.0 + sqrt(5.0)) / 2.0;
Sqrt5minus = (1.0 - sqrt(5.0)) / 2.0;
while (1)
{
fputs ("\nnumber: " , stdout);
f_str[0] = '\';
fgets(f_str, sizeof(f_str) , stdin);
if (strlen(f_str) > 0)
{
f_num = atoi(f_str);
printf("F(%5d) is %20.01f\n" ,
f_num , fiber(f_num));
}
}
return (0);
}
double fiber(int n)
{
return((pow(Sqrt5plus , (double) n)
- pow(Sqrt5minus , (double))
* Invsqrt5);
}
Tom Carrington
Plano, Texas
Dear DDJ,
While Mr. Duvanenko's article was interesting, I thought it was inappropriately applied. If
individual Fibonacci numbers are required, they can be more economically computed using the
following formula:
F(n)=Round(pn/sqrt(5)),
where p = (1 + sqrt(5))/2, is the Golden Ratio.
p{n} can be evaluated using the repeated squaring method described in the article. Or even better, F(n) = trunc (0.5 + exp(n * ln(p) - 0.5 * ln(5))).
Both formulae are derived from the solution to the recursive definition of Fibonacci numbers, i.e.,
F(n) = 1/sqrt(5) * [((1 + sqrt(5))/2)n -
((1 - sqrt(5))/2)n]As the absolute value of the second term is less than 0.5, we can neglect it and round to the nearest integer.
Jeremy Ottenstein
Elizabeth, New Jersey
Dear DDJ,
Ben Myers's WINTHERE program ("Winthere," January 1991) is very useful if you need to know if Windows is running real, standard, or DPMI mode. But if you only need to know if Windows is running or not, there is an easier way. Windows is adding a new environment variable, the "windir," to keep track of the home directory. The variable is added by Windows in runtime and not, as usual, in the AUTOEXEC.BAT. Since any app spawned by DOS EXEC (int 21, function 4B), as programs normally are, inherits the environment block from its parent, windir will be available in all win- and oldapps started under Windows. Note that this is only available in Windows 3.0. Example 2 shows my environment in a DOS-box when running Windows.
C:\DOS>set PROMPT=$p$g PATH=C:\WINDOWS;C:\DOS;C:\PCT;C:\BORLANDC\BIN;C:\WINDEV; C:\T D; TEMP=C:\WINDOWS\TEMP COMSPEC=C:\DOS\COMMAND.COM windir=C:\WINDOWS
The program in Example 3 checks if the "windir" environment variable is present and if it is, the program exits with error code 0, otherwise with error code 255.
// CheckWin check if the environment variable "windir"
// is present.
#include <stdlib.h>
int main(void)
{
if(getenv("windir") = = NULL) return 255; // windir didn't exist
else return 0; // it did
}
The program in Example 4 is very useful in .BAT files for checking if they are running with or without Windows present. This avoids the common problem when you forget that you are in a DOS-box and try to start Windows again, often ending up in a general protection fault destroying whatever was running under Windows. (I renamed WIN.COM to WINDOWS.COM.)
WIN.BAT @ECHO OFF CheckWin IF ERRORLEVEL 255 THEN GOTO W ECHO Windows is already running (Press Ctrl=Esc or Alt+Tab) GOTO END :W WINDOWS :END
Torgil Johnsson
Kista, Sweden
Ben responds: Mr. Johnsson has indeed found a simple way to determine whether Windows 3.0 is running. Just like my original and incomplete WINTHERE solution to the problem, Johnsson's CHECKWIN has advantages and disadvantages.
Copyright © 1991, Dr. Dobb's Journal