jmp start
mess1 db 'Enter 1st number: $'
mess2 db 0a,0d, 'Enter 2nd number: $'
nextline db 0a,0d, '$'
start:
mov ax, 03
int 10h
mov dx, offset mess1
call printstring
call input
sub al, 30h
push ax
mov dx, offset mess2
call printstring
call input
mov bl, al
mov dx, offset nextline
call printstring
sub cl, 30h
sub bl, 30h
pop ax
mov ah, 0
aad
div bl
mov dl, al
add dl, 30h
push ax
call printchar
mov dl, '.'
call printchar
mov ah, 0
pop ax
mov dl, ah
add dl, 30h
call printchar
int 20h
input:
mov ah, 1
int 21h
ret
printstring:
mov ah, 9
int 21h
ret
printchar:
mov ah, 2
int 21h
ret
余数为0时有效,但只有当方程有余数时,余数才会显示错误的数字。
余数是分数的分子。例如,“5/3 = 1 余数为 2”(因为“5 - (1*3) = 2”),所以真实结果将是“1 + 2/3”(或“商 + 余数/除数”)。请注意,许多分数都是循环小数,“1 + 2/3”就是数字 2.666666666...
最简单的显示方式是将其显示为分数(例如打印余数、“/”符号和除数)。
将其打印为小数;您可以重复将“余数/除数”乘以 10 并提取整数部分。例如。 "2*10 / 3 = 6 with the remainder of 2" 所以你可以打印 '6' 然后用新的余数再做一次,对于这个例子来说是一样的,所以你最终会重复打印 '6' (直到您因其他原因停止 - 例如,因为您将其限制为 3 位数)。这对其他分数更有效,例如“1/8”;你会做“1 * 10/8 = 1余数为2; 2 * 10/8 = 2余数为4; 4 * 10/8 = 5余数为0”以获得数字1 , 2 然后 5.
另一个问题是,这将截断为零,人类更喜欢“舍入到最近”——例如,对于“5/3”,你最终会打印“5.666”,而人类会想要“5.667”。要解决这个问题,如果你在小数点后做 3 位数字,你想在开始时将 0.0005 添加到原始余数,然后用分数做它最终是交叉乘法 - 例如“余数/除数 + 1/2000 =(余数*2000)/(除数*2000) + 除数/(除数*2000) = (余数*2000 + 1)/(除数*2000)".
换句话说;如果在将分数转换为三位小数之前执行“remainder = remainder*2000 + 1”和“divisor = divisor * 2000”,您将得到正确舍入的结果。 注意:在某些情况下,此舍入可能会更改整数部分 - 例如值 3.99987654321 应该显示为“4.000”,但如果您不小心,您会显示为“3.000”。幸运的是,您不必为您的情况担心这一点(因为除数始终是 1 到 9 之间的数字)。
装配中;这可能看起来像(NASM 语法,未经测试):
; ax = number1, bl = number2
div bl ;ah = remainder, al = quotient
;Do integer part
mov dl,al ;dl = quotient
call printchar ;Print the quotient
;Prepare for fractional part
shr ax,8 ;ax = remainder (from 0 to 9)
mov cx,2000
mul cx ;dx:ax = ax = remainder*2000 (from 0 to 18000)
lea dx,[ax+1] ;dx = remainder*2000+1 (from 1 to 18001)
mov ax,bx ;ax = divisor (from 1 to 9)
mul cx ;dx:ax = ax = divisor*2000 (from 2000 to 18000)
mov bx,ax ;bx = divisor*2000 (from 2000 to 18000)
mov ax,dx ;ax = remainder*2000+1 (from 1 to 18001)
mov cx,10 ;cx = 10
mov dl,'.'
call printchar ;Print the decimal point
;Do the first fractional digit
mul cx ;dx:ax = (remainder*2000+1) * 10 (from 10 to 180010)
div bx ;ax = (remainder*2000+1) / (divisor*2000); dx = next_remainder (from 0 to 18000)
push dx
mov dl,al
call printchar ;Print the first factional digit
pop ax ;ax = next_remainder (from 0 to 18000)
;Do the second fractional digit
mul cx ;dx:ax = next_remainder * 10 (from 10 to 180000)
div bx ;ax = (next_remainder*10) / (divisor*2000); dx = next remainder
push dx
mov dl,al
call printchar ;Print the second factional digit
pop ax ;ax = next_remainder (from 0 to 18000)
;Do the last fractional digit
mul cx ;dx:ax = next_remainder * 10 (from 10 to 180000)
div bx ;ax = (next_remainder*10) / (divisor*2000); dx = next remainder
mov dl,al
call printchar ;Print the third factional digit
请注意,跟踪变量范围很重要(例如,正如我在上面的评论中所做的那样)以确保没有溢出错误。例如,一个从 10 到 180000 的整数值将不适合 16 位(并且不适合像 AX 这样的 16 位寄存器),我们只是幸运的是指令集使得使用一对对于这些情况,寄存器(“dx:ax”或“DX 中的最高 16 位和 AX 中的最低 16 位”)。