Normal quotes
This commit is contained in:
parent
5e10794a24
commit
18011c595a
352 changed files with 6040 additions and 6040 deletions
44
10-03.md
44
10-03.md
|
|
@ -3,22 +3,22 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
|
||||
Listing 10.2 repeatedly subtracts iS from iL until iL becomes less than
|
||||
or equal to iS. If iL becomes equal to iS, then that’s the GCD;
|
||||
or equal to iS. If iL becomes equal to iS, then that's the GCD;
|
||||
alternatively, if iL becomes *less* than iS, iL and iS switch values,
|
||||
and the process is repeated, as shown in Figure 10.2. The number of
|
||||
iterations this approach requires relative to Listing 10.1 depends
|
||||
heavily on the values of iL and iS, so it’s not always faster, but, as
|
||||
heavily on the values of iL and iS, so it's not always faster, but, as
|
||||
Table 10.1 indicates, Listing 10.2 is generally much better code.
|
||||
|
||||
\
|
||||
**Figure 10.2** *Using repeated subtraction algorithm to find a GCD.*
|
||||
|
||||
Listing 10.2 is a far graver misstep than Listing 10.1, for all that
|
||||
it’s faster. Listing 10.1 is obviously a hacked-up, brute-force
|
||||
it's faster. Listing 10.1 is obviously a hacked-up, brute-force
|
||||
approach; no one could mistake it for anything else. It could be speeded
|
||||
up in any of a number of ways with a little thought. (Simply skipping
|
||||
testing all the divisors between iS and iS/2, not inclusive, would cut
|
||||
the worst-case time in half, for example; that’s not a particularly
|
||||
the worst-case time in half, for example; that's not a particularly
|
||||
*good* optimization, but it illustrates how easily Listing 10.1 can be
|
||||
improved.) Listing 10.1 is a hack job, crying out for inspiration.
|
||||
|
||||
|
|
@ -26,20 +26,20 @@ Listing 10.2, on the other hand, has gotten the inspiration—and largely
|
|||
wasted it through haste. Had Sedgewick not told me otherwise, I might
|
||||
well have assumed that Listing 10.2 was optimized, a mistake I would
|
||||
never have made with Listing 10.1. I experienced a conceptual
|
||||
breakthrough when I understood Sedgewick’s point: A smaller number can
|
||||
breakthrough when I understood Sedgewick's point: A smaller number can
|
||||
be subtracted from a larger number without affecting their GCD, thereby
|
||||
inexpensively reducing the scale of the problem. And, in my hurry to
|
||||
make this breakthrough reality, I missed its full scope. As Sedgewick
|
||||
says on the very next page, the number that one gets by subtracting iS
|
||||
from iL until iL is less than iS is precisely the same as the remainder
|
||||
that one gets by dividing iL by iS—again, this is inherent in the nature
|
||||
of division—and *that* is the basis for Euclid’s algorithm, shown in
|
||||
Figure 10.3. Listing 10.3 is an implementation of Euclid’s algorithm.
|
||||
of division—and *that* is the basis for Euclid's algorithm, shown in
|
||||
Figure 10.3. Listing 10.3 is an implementation of Euclid's algorithm.
|
||||
|
||||
**LISTING 10.3 L10-3.C**
|
||||
|
||||
/* Finds and returns the greatest common divisor of two integers.
|
||||
Uses Euclid’s algorithm: divides the larger integer by the
|
||||
Uses Euclid's algorithm: divides the larger integer by the
|
||||
smaller; if the remainder is 0, the smaller integer is the GCD,
|
||||
otherwise the smaller integer becomes the larger integer, the
|
||||
remainder becomes the smaller integer, and the process is
|
||||
|
|
@ -49,7 +49,7 @@ Figure 10.3. Listing 10.3 is an implementation of Euclid’s algorithm.
|
|||
|
||||
unsigned int gcd(unsigned int int1, unsigned int int2) {
|
||||
unsigned int temp;
|
||||
/* If the two integers are the same, that’s the GCD and we’re
|
||||
/* If the two integers are the same, that's the GCD and we're
|
||||
done */
|
||||
if (int1 == int2) {
|
||||
return(int1);
|
||||
|
|
@ -82,32 +82,32 @@ Figure 10.3. Listing 10.3 is an implementation of Euclid’s algorithm.
|
|||
return(gcd_recurs(smaller_int, temp));
|
||||
}
|
||||
|
||||
As you can see from Table 10.1, Euclid’s algorithm is superior,
|
||||
As you can see from Table 10.1, Euclid's algorithm is superior,
|
||||
especially for large numbers (and imagine if we were working with large
|
||||
*longs!*).
|
||||
|
||||
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *Had I been implementing GCD determination without Sedgewick’s help, I would surely not have settled for Listing 10.1—but I might well have ended up with Listing 10.2 in my enthusiasm over the “brilliant” discovery of subtracting the lesser Using Euclid’s algorithm to find a GCD number from the greater. In a commercial product, my lack of patience and discipline could have been costly indeed.*
|
||||
 *Had I been implementing GCD determination without Sedgewick's help, I would surely not have settled for Listing 10.1—but I might well have ended up with Listing 10.2 in my enthusiasm over the "brilliant" discovery of subtracting the lesser Using Euclid's algorithm to find a GCD number from the greater. In a commercial product, my lack of patience and discipline could have been costly indeed.*
|
||||
------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
\
|
||||
**Figure 10.3** *Using Euclid’s algorithm to find a GCD.*
|
||||
**Figure 10.3** *Using Euclid's algorithm to find a GCD.*
|
||||
|
||||
Give your mind time and space to wander around the edges of important
|
||||
programming problems before you settle on any one approach. I titled
|
||||
this book’s first chapter “The Best Optimizer Is between Your Ears,” and
|
||||
that’s still true; what’s even more true is that the optimizer between
|
||||
this book's first chapter "The Best Optimizer Is between Your Ears," and
|
||||
that's still true; what's even more true is that the optimizer between
|
||||
your ears does its best work not at the implementation stage, but at the
|
||||
very beginning, when you try to imagine how what you want to do and what
|
||||
a computer is capable of doing can best be brought together.
|
||||
|
||||
### Recursion {#Heading6}
|
||||
|
||||
Euclid’s algorithm lends itself to recursion beautifully, so much so
|
||||
Euclid's algorithm lends itself to recursion beautifully, so much so
|
||||
that an implementation like Listing 10.3 comes almost without thought.
|
||||
Again, though, take a moment to stop and consider what’s really going
|
||||
on, at the assembly language level, in Listing 10.3. There’s recursion
|
||||
and then there’s recursion; code recursion and data recursion, to be
|
||||
Again, though, take a moment to stop and consider what's really going
|
||||
on, at the assembly language level, in Listing 10.3. There's recursion
|
||||
and then there's recursion; code recursion and data recursion, to be
|
||||
exact. Listing 10.3 is code recursion—recursion through calls—the sort
|
||||
most often used because it is conceptually simplest. However, code
|
||||
recursion tends to be slow because it pushes parameters and calls a
|
||||
|
|
@ -120,7 +120,7 @@ recursive operations that Listing 10.3 does.
|
|||
**LISTING 10.4 L10-4.C**
|
||||
|
||||
/* Finds and returns the greatest common divisor of two integers.
|
||||
Uses Euclid’s algorithm: divides the larger integer by the
|
||||
Uses Euclid's algorithm: divides the larger integer by the
|
||||
smaller; if the remainder is 0, the smaller integer is the GCD,
|
||||
otherwise the smaller integer becomes the larger integer, the
|
||||
remainder becomes the smaller integer, and the process is
|
||||
|
|
@ -136,7 +136,7 @@ recursive operations that Listing 10.3 does.
|
|||
int2 = temp;
|
||||
}
|
||||
/* Now loop, dividing int1 by int2 and checking the remainder,
|
||||
until the remainder is 0. At each step, if the remainder isn’t
|
||||
until the remainder is 0. At each step, if the remainder isn't
|
||||
0, assign int2 to int1, and the remainder to int2, then
|
||||
repeat */
|
||||
for (;;) {
|
||||
|
|
@ -154,9 +154,9 @@ recursive operations that Listing 10.3 does.
|
|||
|
||||
#### Patient Optimization {#Heading7}
|
||||
|
||||
At long last, we’re ready to optimize GCD determination in the classic
|
||||
At long last, we're ready to optimize GCD determination in the classic
|
||||
sense. Table 10.1 shows the performance of Listing 10.4 with and without
|
||||
Microsoft C/C++’s maximum optimization, and also shows the performance
|
||||
Microsoft C/C++'s maximum optimization, and also shows the performance
|
||||
of Listing 10.5, an assembly language version of Listing 10.4. Sure, the
|
||||
optimized versions are faster than the unoptimized version of Listing
|
||||
10.4—but the gains are small compared to those realized from the
|
||||
|
|
|
|||
Loading…
Reference in a new issue