campo-sirio/gfm/dmbyp10.asm

191 lines
4.0 KiB
NASM
Raw Normal View History

; int _DivUnsArrByPwrOf10(a, n, p)
;
; ARGUMENT
; unsigned a[] n-word number to divide
; int n number of digits
; int p power of 10 to divide by
;
; DESCRIPTION
; Divides a n-word 'a' by a power of 10, c = a / 10^p,
; a>=0, p>0, rounding the result. c is correct only if a / 10^p < 2^79.
;
; SIDE EFFECTS
; The value of a is destroyed (it isn't needed later).
;
; RETURNS
; None. (always succeeds)
;
; AUTHOR
; Jared Levy 7/9/89
; Copyright (C) 1989-90 Greenleaf Software Inc. All Rights Reserved.
;
; MODIFICATIONS
;
;
;
include model.h
include prologue.h
include gm.equ
dseg dmbyp10
p10 dw 1d,10d,100d,1000d,10000d
endds
pseg dmbyp10
cproc _DivUnsArrByPwrOf10,,_dmbyp10
; load parameters
if _LDATA
mov ax, parm4_ ; get power of 10 to divide by
else
mov ax, parm3_ ; get power of 10 to divide by
endif
cmp ax, 0 ; if dividing by 10^0=1,
je qexit ; nothing need be done
if _LDATA
push es
les di, parm1_ ; get pointer to source & destination
mov bx, parm3_ ; get number of digits
else
mov di, parm1_ ; get pointer to source & destination
mov dx, ds
mov es, dx
mov bx, parm2_ ; get number of digits
endif
cmp ax, 4 ; Is the division by less than 10^4?
jle less4d
d10000:
mov cx, 10000d ; divide by 10000=10^4
d4loop:
push ax ; save ax & bx
push bx
call near ptr dmby1a3 ; division
pop bx ; restore ax & bx
pop ax
sub ax, 4 ; 4 less powers of 10 to divide by
cmp ax, 4 ; are there 4 more left to do?
jg d4loop ; yes, do it again
less4d:
mov si, ax
sal si, 1
mov cx, p10[si] ; load correct power of ten
call near ptr dmby1ra3 ; division, with rounding
if _LDATA
pop es
endif
qexit:
cproce
dmby1a3:
dec bx ; digits go from 0 to n-1
sal bx, 1 ; want bytes rather than words
;/* skip initial zeroes */
; for(;(q>0)&&(c[q-1]==0);q--);
;
; if (q == 0)
; return(0);
; q--; /* q will be used for subscript */
zeroloop:
mov ax, word ptr es:[di+bx] ; get digit
cmp ax, 0 ; is digit zero?
jne nonzero ; if non-zero, begin divide
dec bx ; next word
dec bx
cmp bx, 0 ; last digit?
jge zeroloop ; if not, process next digit
xor ax, ax ; otherwise, remainder 0
jmp short exit1 ; && division through (0/c=0)
; bl = (unsigned long) b;
; while (q>=0) {
; k = (unsigned long *) &r[q];
; cl = *k / bl;
; c[q] = (unsigned) cl;
; r[q] = (unsigned) (*k - cl * bl);
; q--;
; }
nonzero:
xor dx,dx ; high word zero in first divide
divloop:
div cx ; divide digit
mov word ptr es:[di+bx], ax ; store quotient digit
cmp bx, 0 ; last digit?
je exit2 ; if so, division complete
dec bx ; next digit
dec bx
mov ax, word ptr es:[di+bx] ; get digit
jmp short divloop ; process digit
exit2:
mov ax, dx ; return remainder
exit1:
ret
dmby1ra3:
dec bx ; digits go from 0 to n-1
sal bx, 1 ; want bytes rather than words
;/* skip initial zeroes */
; for(;(q>0)&&(c[q-1]==0);q--);
;
; if (q == 0)
; return(0);
; q--; /* q will be used for subscript */
rzeroloop:
mov ax, word ptr es:[di+bx] ; get digit
cmp ax, 0 ; is digit zero?
jne rnonzero ; if non-zero, begin divide
dec bx ; next word
dec bx
cmp bx, 0 ; last digit?
jge rzeroloop ; if not, process next digit
; xor ax, ax ; otherwise, remainder 0
jmp short rexit1 ; && division through (0/c=0)
; bl = (unsigned long) b;
; while (q>=0) {
; k = (unsigned long *) &r[q];
; cl = *k / bl;
; c[q] = (unsigned) cl;
; r[q] = (unsigned) (*k - cl * bl);
; q--;
; }
rnonzero:
xor dx,dx ; high word zero in first divide
rdivloop:
div cx ; divide digit
mov word ptr es:[di+bx], ax ; store quotient digit
cmp bx, 0 ; last digit?
je rexit2 ; if so, division complete
dec bx ; next digit
dec bx
mov ax, word ptr es:[di+bx] ; get digit
jmp short rdivloop ; process digit
; round up if remainder > (divisor-1)/2
rexit2:
dec cx ; set cx = (cx-1)/2
sar cx, 1
cmp dx, cx ; test for rounding up
ja inclp ; if remainder is large, round up
ret
inclp:
inc word ptr es:[di]
jnz rexit1
inc di
inc di
jmp short inclp
rexit1:
ret
endps
end