超过32位的MIPS乘法



对于一个赋值,我需要开发一个递归算法。如果给了一个输入字符串,我会打印出与基30对应的无符号十进制整数由字符串表示的数字。(a-10;b-11;…)例如:

给定输入:

"AAAAAAAAAAaaaaaaaaaa">

预期输出:

120233944862068965517241379310

其他指令:输入中最多允许20个字符。输入字符串的内存地址通过寄存器传递到子程序中,十进制整数通过堆栈返回(因为寄存器可能不足以保存结果)。

我理解MIPS的递归部分,但寄存器只能容纳32位。因此,我们无法将结果存储在寄存器中,因为它较大。什么是分解问题的有效方法,我可以通过乘法进行计算?

ExA'(10)*30^19+'A'(10*30^18+…+'a'(10)*30^0

不只是给我代码,因为这是一项任务,但如果有人能给我指明正确的方向,那就太好了!

你可以有和寄存器或内存一样大的数字,想想小学乘法,想想基数二如何简化它。

abcdef
*    111101
============
abcdef
000000
abcdef
abcdef
abcdef
abcdef

但是如果我只有2位寄存器呢?

你会做这样的事情:

ab cd ef
0 00 00 0
ab cd ef
a bc de f
ab cd ef
a bc de f
===============

你可以一次坐两排。

从小学的十六进制数来看,我想说乘以16位的数字,但我只有一个8位*8位=16位的乘法指令:

abcd * 1234 =
((ab*(2^8))+(cd*(2^0))) * ((12*(2^8))+(34*(2^0)) = 
((ab*x)+(cd*y)) * ((12*x)+(34*y) = 
ab*12*x*x + ab*34*x*y + cd*12*x*y + cd*34*y*y =

x和y只是2的幂,但更重要的是,它们将结果放在8、16或8位边界的幂以上。现在可以用8位*8位=16位的乘法或16位*16位=16比特的乘法来完成数字,并且填充高位。然后你跟踪谁降落在哪里,有一些附加的携带,可以添加到下一组。

这就是你如何利用你在学校学到的知识,将这些东西与你的寄存器/指令级联。

所以你可以建立一个大的乘法器,我假设你知道如何级联加法,或者可以用类似的方法计算它;只是";使用它。

但你的问题正如你所说的那样。(10) *30^19+(10)*30^18等等。

#include <stdio.h>
int main ( void )
{
unsigned int ra;
unsigned int rb;
unsigned int rc;
for(ra=1;ra<6;ra++)
{
rc=1;
for(rb=0;rb<ra;rb++)
{
rc*=30;
}
printf("%2u 0x%08X %un",ra,rc,rc);
}
return(0);
}
1 0x0000001E 30
2 0x00000384 900
3 0x00006978 27000
4 0x000C5C10 810000
5 0x0172C9E0 24300000

30是352。它在二进制中看起来一点也不漂亮,在十进制中看起来也不差。也许这里有个诀窍。

abc = 10*30*30 + 11*30 + 12*0
9000 + 330 + 12
9312

我还没看到。

但如果你想想3,5,2

在二进制x3中是(x<<1)+x;x5是(x<<2)+x并且x*2=x<lt;1.

如果十进制(以10为基数)1234

x = 1;
for each digit that remains in the string
x = x * 10; //shift left one number place
x = x + 2; //next digit
...

将基数10转换为二进制

x = 1;
x = (x<<3)+(x<<1); //x = x * 10;
x = x + 2;
x = (x<<3)+(x<<1);
x = x + 3;
x = (x<<3)+(x<<1);
x = x + 4;

x = 0;
x = (x<<3)+(x<<1);
x = 1;
x = (x<<3)+(x<<1);
x = x + 2;
x = (x<<3)+(x<<1);
x = x + 3;
x = (x<<3)+(x<<1);
x = x + 4;

x = 0;
y = x<<3;
x = y + x<<1;
x = x + 1;
y = x<<3;
x = y + x<<1;
x = x + 2;
y = x<<3;
x = y + x<<1;
x = x + 3;
y = x<<3;
x = y + x<<1;
x = x + 4;

如图所示,从30到二进制,而不是从10到二进制,很容易形成一个循环。移位小数字很容易级联到尽可能多的寄存器或内存位置。加法步骤只能执行一位,因此可以轻松地级联到尽可能多的寄存器/内存位置。因此,一个基数为10到基数为2的长于一个寄存器中有位的寄存器并不困难。现在,把这个很长的二进制数变成基数10打印出来,是的,这是一个新问题。

也许这里的技巧是伪bcd类型的方法,每个十进制数字一个半字节,你正在做这种事情:

1 0x0000001E 30
2 0x00000384 900
3 0x00006978 27000
4 0x000C5C10 810000
5 0x0172C9E0 24300000

"abc";10、11、12

x = 0x0
x = x * 0x30 = (x<<5) + (x << 4); //hmmm is that right?
x = x + 0x10;
...

但对于所有这些加法,你必须从右到左覆盖bcd溢出,所以0x1A变成0x20,因为0xA比9大一,所以这是一个进位到下一个半字节。这很难看,但如果每个BCD数字都是8位呢?

这就是我正在思考的路径,如果你要为自己构建一个多寄存器的大乘法器,需要多少寄存器/内存位置才能处理30^19次方?这就是它必须有多大,但如果你建造了它,那么它将很容易使用。把它变成二进制。现在你要建立一个大的除法器,把它从二进制到10进制?

这是可行的,你这样做的长除法风格10是0b1010你真的在比特下面走了101,每一个比特你得到一个0或1。它的长除法,你可以在一个循环中编程,从msbit开始一次从分子中提取一个比特,并将比特的累积与0b101或0b1010进行比较,它将小于10的2倍,所以结果是累积1或0,就像长除法一样你边做边减去0乘以10或1乘以10。

0x1D/10

11101

如果你愿意的话,我们一次取下一个分子位,就像累加器中的长除法一样,并将其与分母进行比较

1与1010相比为0余数1下一位11与1010相比为0余数11111与1010相比为0余数1111110与1010相比为1余数1001001与1010相比为0余数1001

结果为00010或2,0x1D/10=29/10=2易于制造的累加器只需要是4位即可轻松地一次遍历一位通过无限数量的32位寄存器或存储位置。但你必须做无数次

1234小数=0x4D2

0x4D2 / 10 = 0x7B remainder 4
0x7B / 10 = 0xC remainder 3
0xC / 10 = 0x1 remainder 2
0x1 / 10 = 0 remainder 1

所以我们完成了,结果是1234小数。

您从0x4D2开始,得到0x7B和4,但这不是一小部分比特,而是几十/几百个比特。

蛮力,如果你能使乘法器以二进制级联的方式满足你所需要的32位字的数量,并且没有错误,那么除法就不那么难编码了。你可以用乘法运算。

30^20=3.4..*10^29

我的大脑没有完全计算出你需要存储这个数字的位数/字数。

不管怎样,是的,你可以级联一个32位*32位=32位(一次16位)或32位*33位=64位(一次32位)的乘法器,只要你有内存(很快就会用完寄存器,用寄存器进行乘法和加法,用进位加法,用内存保存实际数字)。最终以基数2的结果结束。然后,你可以制作一个长除法算法,并反复计算,直到分子为0。作业需要乘法吗?

最新更新