Use backtick code blocks for syntax highlighting
This commit is contained in:
parent
8ed9dea394
commit
f658bfbb40
203 changed files with 26546 additions and 25801 deletions
164
10-04.md
164
10-04.md
|
|
@ -12,93 +12,95 @@ pages: 200-203
|
|||
|
||||
**LISTING 10.5 L10-5.ASM**
|
||||
|
||||
; 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);
|
||||
```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
|
||||
; 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
|
||||
.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:
|
||||
;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
|
||||
; 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
|
||||
;—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
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in a new issue