为什么签名的mul / div有不同的机器指令?

时间:2018-01-16 20:22:48

标签: assembly integer-arithmetic

我一直认为有符号的乘法和除法需要与相应的无符号运算不同的电路逻辑。在另一个论坛上,有人说,无符号ALU可以在不对签名参数进行任何修改的情况下使用,并给出有效结果。

我刚用一个小程序测试了这个

#include <stdio.h>

void main()
{
    short a, b;
     long long c;

    c = 0;
    a = -32768;
    do
    {
        b = -32768;
        do
            if( (int)((unsigned)a * (unsigned)b) != ((int)a * b) )
                ++c;
        while( ++b != -32768 );
    } while( ++a != -32768 );

    printf( "%.0lf\n", (double)c );
}

这打印为零,即乘法的工作方式与上述假设相同。那么为什么对于有符号和无符号乘法有不同的指令,以及它如何在电路逻辑中表示?

我没有谈论分歧。我是否正确地假设,我之前的假设是至少需要不同的电路逻辑?

2 个答案:

答案 0 :(得分:3)

取决于参数的大小。如果你将两个8位值相乘,需要16位来存储结果最坏的情况吗? 0xFF * 0xFF = 0xFE01。 255 * 255 = 65025。

从小学开始,我们如何手工繁殖?我有两位,两位数

   ab
*  cd
======

让我们说cd就是让这个显而易见的事情。

    ab
 *  11
======
   0ab
+  ab 
======

如果我们认为这些是无符号数,那么ab和cd左边的位用零填充。但如果这些是带符号的数字,则这些位是符号扩展

  000ab
* 000cd
========

  xxxab
* yyycd
=======

如果我取两位操作数和两位结果,那么这无关紧要

    ab
 *  11
======
    ab
+   b 
======

总和中的位不关心。但如果我想要一个两位操作数和一个4位结果就很重要。

如果你想要一个32位分母,那么你想用64位分子开始除法,所以32位除以32位是分子有符号还是无符号?当你将它填充到64位以进行除法时,你是签名扩展它还是零填充它(有符号或无符号)。结果各不相同。

有些指令集没有二对一的操作数都是相同的大小,所以你“简单地”必须综合这个,但你按照小学的知识来做。

加法和减法不关心有符号vs无符号他们不知道,减法使用加法器,二进制补码的美,你反转并添加一个所以你反转第二个操作数,然后将1加入进位中然后添加lsbit,将加法器转换为减法器。两个补充照顾其余的,结果只是两种方式。无符号溢出vs有符号溢出很重要,如果两者都是计算的,那么你的加法器就可以做到。无符号溢出是msbit的进位,有符号是进位和进位msbit的比较,也可以从输入的msbits和结果中确定。

答案 1 :(得分:1)

  

在另一个论坛上,有人说,无符号ALU可以在不对签名参数进行任何修改的情况下使用,并提供有效结果。

要理解这个矛盾,我们应该记住,一个数字(这里是一个十进制数字)有&#34;隐含&#34;左边和右边的数字:

12345 = 00...0000000012345.000000000...00

正和无符号二进制数也是如此;在这种情况下,隐含数字为0:

01110100 = 00...0000000001110100.0000...00

对于存储为二进制补码的负数,左侧的隐含数字是1,而不是零:

10110100 = 11...1111111110110100.0000...00

每当其中一个&#34;隐含&#34;左侧的数字会影响操作的结果,我们需要一个无符号和有符号的操作变体:

<强>移

向右移动右侧的隐含数字(小数点后)将影响结果;这总是0。

然而,向右移动左侧的第一个隐含数字将影响结果;确实有两个&#34;右移&#34;运营:&#34; SRL&#34; (未签名)和&#34; SRA&#34; (签名)。

加法,减法和乘法

在这些情况下,结果也会有所不同:

1111 + 0011 = 11111 + 00011 = 00010 (signed)
1111 + 0011 = 01111 + 00011 = 10010 (unsigned)

然而,大多数CPU提供的操作只会返回与输入数据一样多的位:如果要添加两个8位数字,则只获得结果的低8位,而不是整个9位。低8位在有符号和无符号运算之间没有区别。

如果有一个CPU可以添加两个8位数字,返回16位结果,那么这个CPU需要一个&#34; unsigned add&#34;和#34;签名添加&#34;指令!

乘法也是如此。然而,许多(大多数)CPU的工作方式如下:它们将两个32位数相乘,结果不是低32位而是全64位 - 所以&#34;有符号乘法&#34;和#34;无符号乘法&#34;需要说明。

但是,很少有CPU将两个32位数相乘,只返回结果的低32位。这些CPU只需要一个&#34;乘法&#34;指令。

<强>司

除以8与右移3位的操作相同。

这意味着左侧的三个隐含数字将被移位,这意味着左侧的隐含数字会对结果产生影响。

因此,您总是需要&#34;无符号划分&#34;和#34;签署的划分&#34;操作