144 lines
No EOL
5.8 KiB
Markdown
144 lines
No EOL
5.8 KiB
Markdown
---
|
|
title: Michael Abrash's Graphics Programming Black Book, Special Edition
|
|
author: Michael Abrash
|
|
date: '1997-07-01'
|
|
isbn: '1576101746'
|
|
publisher: The Coriolis Group
|
|
category: 'Web and Software Development: Game Development,Web and Software Development:
|
|
Graphics and Multimedia Development'
|
|
chapter: '10'
|
|
pages: 200-203
|
|
---
|
|
|
|
**LISTING 10.5 L10-5.ASM**
|
|
|
|
```nasm
|
|
; Finds and returns the greatest common divisor of two integers.
|
|
; 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
|
|
; repeated. Avoids code recursion.
|
|
;
|
|
;
|
|
;
|
|
; C near-callable as:
|
|
; unsigned int gcd(unsigned int int1, unsigned int int2);
|
|
|
|
; Parameter structure:
|
|
parms struc
|
|
dw ? ;pushed BP
|
|
dw ? ;pushed return address
|
|
int1 dw ? ;integers for which to find
|
|
int2 dw ? ; the GCD
|
|
parms ends
|
|
|
|
.model small
|
|
.code
|
|
public _gcd
|
|
align 2
|
|
_gcd proc near
|
|
push bp ;preserve caller's stack frame
|
|
mov bp,sp ;set up our stack frame
|
|
push si ;preserve caller's register variables
|
|
push di
|
|
|
|
;Swap if necessary to make sure that int1 >= int2
|
|
mov ax,int1[bp]
|
|
mov bx,int2[bp]
|
|
cmp ax,bx ;is int1 >= int2?
|
|
jnb IntsSet ;yes, so we're all set
|
|
xchg ax,bx ;no, so swap int1 and int2
|
|
IntsSet:
|
|
|
|
; Now loop, dividing int1 by int2 and checking the remainder, 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.
|
|
GCDLoop:
|
|
;if the remainder of int1 divided by
|
|
; int2 is 0, then int2 is the gcd
|
|
sub dx,dx ;prepare int1 in DX:AX for division
|
|
div bx ;int1/int2; remainder is in DX
|
|
and dx,dx ;is the remainder zero?
|
|
jz Done ;yes, so int2 (BX) is the gcd
|
|
;no, so move int2 to int1 and the
|
|
; remainder to int2, and repeat the
|
|
; process
|
|
mov ax,bx ;int1 = int2;
|
|
mov bx,dx ;int2 = remainder from DIV
|
|
|
|
;—start of loop unrolling; the above is repeated three times—
|
|
sub dx,dx ;prepare int1 in DX:AX for division
|
|
div bx ;int1/int2; remainder is in DX
|
|
and dx,dx ;is the remainder zero?
|
|
jz Done ;yes, so int2 (BX) is the gcd
|
|
mov ax,bx ;int1 = int2;
|
|
mov bx,dx ;int2 = remainder from DIV
|
|
;—
|
|
sub dx,dx ;prepare int1 in DX:AX for division
|
|
div bx ;int1/int2; remainder is in DX
|
|
and dx,dx ;is the remainder zero?
|
|
jz Done ;yes, so int2 (BX) is the gcd
|
|
mov ax,bx ;int1 = int2;
|
|
mov bx,dx ;int2 = remainder from DIV
|
|
;—
|
|
sub dx,dx ;prepare int1 in DX:AX for division
|
|
div bx ;int1/int2; remainder is in DX
|
|
and dx,dx ;is the remainder zero?
|
|
jz Done ;yes, so int2 (BX) is the gcd
|
|
mov ax,bx ;int1 = int2;
|
|
mov bx,dx ;int2 = remainder from DIV
|
|
;—end of loop unrolling—
|
|
jmp GCDLoop
|
|
|
|
align2
|
|
Done:
|
|
mov ax,bx ;return the GCD
|
|
pop di ;restore caller's register variables
|
|
pop si
|
|
pop bp ;restore caller's stack frame
|
|
ret
|
|
_gcd endp
|
|
end
|
|
```
|
|
|
|
Assembly language optimization is pattern matching on a local scale.
|
|
Frankly, it's also the sort of boring, brute-force work that people are
|
|
lousy at; compilers could out-optimize you at this level with one pass
|
|
tied behind their back *if* they knew as much about the code you're
|
|
writing as you do, which they don't.
|
|
|
|
> 
|
|
> Design optimization—conceptual breakthroughs in understanding the
|
|
> relationships between the needs of an application, the nature of the
|
|
> data the application works with, and what the computer can do—is global
|
|
> pattern matching.
|
|
|
|
Computers are *much* worse at that sort of pattern matching than humans;
|
|
computers have no way to integrate vast amounts of disparate
|
|
information, much of it only vaguely defined or subject to change.
|
|
People, oddly enough, are *better* at global optimization than at local
|
|
optimization. For one thing, it's more interesting. For another, it's
|
|
complex and imprecise enough to allow intuition and inspiration, two
|
|
vastly underrated programming tools, to come to the fore. And, as I
|
|
pointed out earlier, people tend to perform instantaneous solutions to
|
|
even the most complex problems, while computers bog down in
|
|
geometrically or exponentially increasing execution times. Oh, it may
|
|
take days or weeks for a person to absorb enough information to be able
|
|
to reach a solution, and the solution may only be near-optimal—but the
|
|
solution itself (or, at least, each of the pieces of the solution)
|
|
arrives in a flash.
|
|
|
|
Those flashes are your programming pattern matcher doing its job. *Your*
|
|
job is to give your pattern matcher the opportunity to get to know each
|
|
problem and run through it two or three times, from different angles, to
|
|
see what unexpected solutions it can come up with.
|
|
|
|
Pull back the reins a little. Don't measure progress by lines of code
|
|
written today; measure it instead by overall progress and by quality.
|
|
Relax and listen to that quiet inner voice that provides the real
|
|
breakthroughs. Stop, look, listen—and think. Not only will you find that
|
|
it's a more productive and creative way to program—but you'll also find
|
|
that it's more fun.
|
|
|
|
And think what you could do with all those extra computer years! |