使用 8086 汇编计算 10 的阶乘 [英] Computing the factorial of 10 using 8086 assembly

查看:25
本文介绍了使用 8086 汇编计算 10 的阶乘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用汇编语言来解决这个问题.问题是我不能存储 10 个!在 al 中,我的代码用于查找 5 的阶乘.如何存储 10 的结果!在寄存器中?当我找到 5 的阶乘时,我可以在 al 中清楚地看到结果,因为 120 可以存储在 al 中.

I have been trying to solve this using assembly language. The thing is I cannot store the 10! In al and my code works for finding factorial of 5. How do I store my result of 10! In a register? When I find factorial of 5 I can see the result clearly in al because 120 can be stored in al.

任何帮助将不胜感激.

这是我的 5 代码!

 org 100h
.DATA
ANS DB ? 
.CODE
MAIN PROC
    MOV AX,@DATA
    MOV DS,AX
    MOV AL,5                     
    MOV CL,4
    MOV BL,AL
    SUB BL,1
    L:
    MUL BL
    SUB  BL,1
    LOOP L

    MOV ANS,AL
    END MAIN
ret

推荐答案

10! is 10*9*8*7*6*5*4*3*2*1.

为了速度,您可以通过在大 * 小"中执行中间值来最小化它们的大小.对,例如 (1*10) * (2*9) * (3*8) * (4*7) * (5*6).

For speed you can minimize the size of intermediate values by doing them in "big * little" pairs, like (1*10) * (2*9) * (3*8) * (4*7) * (5*6).

您可以将这些对描述为表达式 temp = x * (11 - x)(x 的值从 1 到 5).如果您知道 x 的结果(例如 temp = 10 if x == 1),那么下一对的结果可以从前一对的结果.例如:

You can describe these pairs as the expression temp = x * (11 - x) (with values of x from 1 to 5). If you know the result for x (e.g. temp = 10 if x == 1) then the result of the next pair can be derived from the result of the previous pair. E.g.:

temp1 = x * (11 - x)

temp2 = (x+1) * (11 - (x+1))
      = (x+1) * (11 - x - 1)
      = x * (11 - x - 1) + (11 - x - 1)
      = x * (11 - x) - x + (11 - x - 1)
      = temp1 - x + (11 - x - 1)
      = temp1 - x - x + 11 -1
      = temp1 - (x << 1) + 10

换句话说;如果你知道pair 1"的结果(或 1*10) 将是 10,然后您可以通过执行 (10) - (1<<1) + 10 = 18;,然后通过(18) - (2<<1) + 10 = 24计算下一对的结果,然后...

In other words; if you know that the result of "pair 1" (or 1*10) will be 10, then you can calculate the result of the next pair (or 2*9) by doing (10) - (1<<1) + 10 = 18;, then calculate the result of the next pair by doing (18) - (2<<1) + 10 = 24, then...

请注意,以这种方式计算对不涉及乘法.在计算成对的中间结果(仅使用加/减)后,您最终会得到10!= 10*18*24*28*30".

Note that there is no multiplication involved for calculating the pairs this way. After calculating the intermediate results from pairs (with add/sub alone), you end up with "10! = 10*18*24*28*30".

为了更多乐趣;您可以证明所有这些中间结果将始终是偶数.这意味着你可以作弊并说10!= 10*18*24*28*30 = 5*9*12*14*15(1+1+1+1+1) = 5*9*12*14*15 <<5";当您考虑做更昂贵的太大"时,这一点很重要;稍后乘法.

For more fun; you can prove that all of these intermediate results will always be even. That means you can cheat and say "10! = 10*18*24*28*30 = 5*9*12*14*15 << (1+1+1+1+1) = 5*9*12*14*15 << 5"; which is important when you're looking at doing more expensive "too big" multiplications later.

因为这些中间值适合 8 位,所以我们可以做成对对"只需两个 16 位乘法."<代码>10!= (5*9) * (12*14) * 15 <<5 = 45 * 168 * 15 <<5".

Because these intermediate values fit in 8 bits, we can do "pairs of pairs" just with two 16-bit multiplications. "10! = (5*9) * (12*14) * 15 << 5 = 45 * 168 * 15 << 5".

通过乘以最小的中间值,结果仍然适合 16 位."<代码>10!= 45 * 168 * 15 <<5 = (45*15) * 168 <<5 = 675 * 168 <<5".

By multiplying the smallest intermediate values the result will still fit in 16 bits. "10! = 45 * 168 * 15 << 5 = (45*15) * 168 << 5 = 675 * 168 << 5".

现在你只需要做一次乘法,结果是 32 位,但两个操作数都是 16 位.实模式通过一个 mul 指令完美地处理了这个问题,所以没有问题;只是结果将存储在 dx:ax 中.具体来说,对于 675 * 168,dx:ax 中的结果将是 113400(或 0x1BAF8,或 dx 中的 0x0001 和 ax 中的 0xBAF8).

Now you only need to do one multiplication where the result is 32 bits but both operands are 16 bit. Real mode handles this perfectly fine with a single mul instruction so that is no problem; it's just that the result will be stored in dx:ax. Specifically, for 675 * 168 the result in dx:ax will be 113400 (or 0x1BAF8, or 0x0001 in dx and 0xBAF8 in ax).

这给了我们10!= 113400 <<5".为此,在旧的仅限 16 位"上会有点尴尬.CPU(您不能在实模式下仅使用 32 位指令,包括 32 位 mul).8086 的最佳方法可能是使用另一个寄存器进行右移然后".将 ax 中的位转换为 dx;喜欢:

This gives us "10! = 113400 << 5". For this it'll be a little awkward on an old "16-bit only" CPU (where you can't just use 32-bit instructions in real mode, including 32-bit mul). The best way for 8086 is probably using another register for a "right shift then or" to get the bits from ax into dx; like:

mov cl,5
mov bx,ax
shl dx,cl
shl ax,cl
mov cl,16-5
shr bx,cl
or dx,bx

对于 80186 及更高版本,您可以使用立即转移"做得更好一些避免使用 cl,如 shl dx,5,但 8086 不支持.

For 80186 and later you can do it slightly better using "shift by immediate" to avoid using cl, like shl dx,5, but that isn't supported for 8086.

结果将是 3628800,这是正确的答案.

The result will be 3628800, which is the right answer.

请注意,可以调整相同的方法来处理其他阶乘 - 对于奇数阶乘,您可以忽略 *1,它实际上并没有做任何事情来确保对的中间结果仍然是偶数(例如 "11! = 1 * (2*11) * (3*10) * (4*9) * (5*8) * (6*7) = (2*11) * (3*10)*(4*9)*(5*8)*(6*7)").对于所有阶乘 (n!);对的中间计算可以描述为 temp2 = temp1 - (x <<1) + (n & (~1)) (我认为 - 实际上没有检查);并且最终的移位将始终是 n/2 向下舍入(例如对于 11!,移位计数将为(int)11/2 = (int)5.5 = 5).

Note that this same approach can be tweaked to handle other factorials - for odd factorials you can ignore the *1 that doesn't actually do anything to ensure the intermediate results from pairs are still even (e.g. "11! = 1 * (2*11) * (3*10) * (4*9) * (5*8) * (6*7) = (2*11) * (3*10) * (4*9) * (5*8) * (6*7)"). For all factorials (n!); the intermediate calculation of pairs can be described as temp2 = temp1 - (x << 1) + (n & (~1)) (I think - didn't actually check); and the final shift will always be n/2 rounded down (e.g. for 11! the shift count will be "(int)11/2 = (int)5.5 = 5).

仅使用 16 位乘法,它应该可以一直使用到 15!.16个!和更大,相同的技术可以最大限度地减少所需的 32 位乘法次数.

With 16-bit multiplication alone it should be good up until 15!. For 16! and larger, the same techniques work to minimize the number of 32-bit multiplications needed.

这篇关于使用 8086 汇编计算 10 的阶乘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆