Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>One good example of why named constants are beneficial comes from the excellent book <a href="http://plan9.bell-labs.com/cm/cs/tpop/" rel="noreferrer">The Practice of Programming</a> by Kernighan and Pike.</p> <blockquote> <h3>§1.5 Magic Numbers</h3> <p>[...] This excerpt from a program to print a histogram of letter frequencies on a 24 by 80 cursor-addressed terminal is needlessly opaque because of a host of magic numbers:</p> <pre><code>... fac = lim / 20; if (fac &lt; 1) fac = 1; for (i = 0, col = 0; i &lt; 27; i++, j++) { col += 3; k = 21 - (let[i] / fac); star = (let[i] == 0) ? ' ' : '*'; for (j = k; j &lt; 22; j++) draw(j, col, star); } draw(23, 2, ' '); for (i = 'A'; i &lt;= 'Z'; i++) printf("%c ", i); </code></pre> <p>The code includes, among others, the numbers 20, 21, 22, 23, and 27. They're clearly related...or are they? In fact, there are only three numbers critical to this program: 24, the number of rows on the screen; 80, the number of columns; and 26, the number of letters in the alphabet. But none of these appears in the code, which makes the numbers that do even more magical.</p> <p>By giving names to the principal numbers in the calculation, we can make the code easier to follow. We discover, for instance, that the number 3 comes from (80 - 1)/26 and that let should have 26 entries, not 27 (an off-by-one error perhaps caused by 1-indexed screen coordinates). Making a couple of other simplifications, this is the result:</p> <pre><code>enum { MINROW = 1, /* top row */ MINCOL = 1, /* left edge */ MAXROW = 24, /* bottom edge (&lt;=) */ MAXCOL = 80, /* right edge (&lt;=) */ LABELROW = 1, /* position of labels */ NLET = 26, /* size of alphabet */ HEIGHT = (MAXROW - 4), /* height of bars */ WIDTH = (MAXCOL - 1)/NLET /* width of bars */ }; ... fac = (lim + HEIGHT - 1) / HEIGHT; if (fac &lt; 1) fac = 1; for (i = 0; i &lt; NLET; i++) { if (let[i] == 0) continue; for (j = HEIGHT - let[i]/fac; j &lt; HEIGHT; j++) draw(j+1 + LABELROW, (i+1)*WIDTH, '*'); } draw(MAXROW-1, MINCOL+1, ' '); for (i = 'A'; i &lt;= 'Z'; i++) printf("%c ", i); </code></pre> <p>Now it's clearer what the main loop does; it's an idiomatic loop from 0 to NLET, indicating that the loop is over the elements of the data. Also the calls to <code>draw</code> are easier to understand because words like MAXROW and MINCOL remind us of the order of arguments. Most important, it's now feasible to adapt the program to another size of display or different data. The numbers are demystified and so is the code.</p> </blockquote> <p>The revised code doesn't actually use MINROW, which is interesting; one wonders which of the residual 1's should be MINROW.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload