LETTERS

Cordic Connections

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.

The Mandarin Middle Management Conspiracy

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

Raising Questions on Raising Matrices

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.

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

Are Your Windows Running?

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.

Example 2: The DOS-box environment with Windows running

  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.

Example 3: Program to check for windir

  // 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.)

Example 4: Program to check whether .BAT files are running with or without Windows

  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.

  1. CHECKWIN relies on an apparently undocumented feature of Windows 3.0, though one that can readily be verified without resorting to reverse engineering methods. Since the windir environment variable is undocumented, Microsoft has no obligation to carry it forward to new releases of Windows. When I first broached this problem to Microsoft via their online service over a year ago, the Microsoft response suggested something similar to Mr. Johnsson's approach, but it was vaguely stated, and there was no mention of the windir environment variable.
  2. The method in CHECKWIN is not robust. It does not guarantee that Windows is running. For example, I could set the windir variable with a C setenv function call made from a non-Windows program, and this would mislead any program that used the CHECKWIN method. In passing, note that the DOS SET command cannot be used to set an environment variable which contains any lower case characters, because SET converts both environment variable and environment string to upper case.
  3. On the plus side, the CHECKWIN approach was properly both from Windows and DOS apps. I put a similar getenv function call into one of my Windows apps, and it returned the path from which Windows was launched. This implies that it would also work when used within device drivers and other system software that needs to know whether Windows is running or not. Also in passing, setting an environment variable is not a foolproof method for making known the path from which Windows is launched. Environment space in a PC is limited, and any software that uses environment variables always runs the risk of exceeding available environment space. Many Microsoft products use one or more environment variables. From a human factors standpoint this is not desirable, especially for novice users who may have real difficulty figuring out what did not work and why. There are several good techniques for keeping track of this sort of information without using environment variables.
I have reservations about using the CHECKWIN approach in commercial software. Until Microsoft defines a robust API for detecting the presence of Windows, I cannot offer a better solution other than combining my original WINTHERE code with the getenv function as used by CHECKWIN. The combined result still has holes in it, but it is better than nothing. Let's hope that Microsoft will address this issue with Windows 3.1, which is expected to be in beta testing in late June or early July 1991.


Copyright © 1991, Dr. Dobb's Journal