【问题标题】:Overflow/underflow in unsigned numbers无符号数的上溢/下溢
【发布时间】:2011-10-21 01:34:03
【问题描述】:

因此,如果在无符号数的加法中出现 1 进位,则表示溢出,如果在减法中出现 0 进位,则表示下溢。不过,这是否适用于所有情况?

如果你打出 5-0: 0101 -0000

= 0101 +(1111 + 1)

= 0101 +0000

= 0101...这里有一个零进位,而不是 1。如何解释这种情况?有其他方法吗?

(使用 MIPS 架构,或其他)

---编辑

感谢阿马丹。不过,我理解那部分。我的问题是零似乎是一个特例。它似乎不遵循正常数字的做法:在我上面的示例中,没有 1 的进位。

我目前正在使用 ALU 进行电路设计,并尝试实现溢出检测,当出现这种情况时,它并没有遵循其他情况。

我们假设通过减法,第二个操作数在进入 ALU(然后添加到第一个操作数)之前被预先反转(二进制补码)。因此,每当减法的“invert_b”设置为 1 时,b 就会反转,我们假设我们要检查的情况是减法,它的进位应该是 1。

【问题讨论】:

  • 我不明白这个问题。添加正数和负数永远不会导致下溢/溢出。
  • 添加了更多信息.. 希望它能解决这个问题。
  • @davin 说了什么。我不知道他们是如何在 CPU 中做到这一点的,但是反转零应该总是给你一个进位 (1111 + 1 = (1)0000),因此如果你使用二进制,-0 = 0 并不完全正确用于减法目的的补码。
  • 但是,如果我们在做减法之前转换为二进制补码,0 再次只是 0000.. 然后我们在此之后添加,因为电路认为我们正在减去它,如果没有,它将寻找溢出携带...这是我感到困惑的地方。我希望我没有忽略你们已经提到的事情。
  • @Risshuu,这不仅仅是 0000。减法导致加法器将原始数字和1111+1相加,即0000进位为1,因此进位与加0000的正常情况相反。因此结果相反,即是有道理的,因为如果在 +0 的情况下会溢出,则会出现下溢。由于在 +0 的原始情况下,进位不能为 1,因此不会溢出,并且通过对称性,带有 1 的进位的 +0000 的情况将始终进位 1,因此永远不会下溢。

标签: numbers overflow mips unsigned underflow


【解决方案1】:

我相信 msbit 执行位本身涵盖了无符号和有符号的,您查看 msbit 的进位和进位是否不同。

5-0 不会溢出,因为结果符合可用位数。同样的方式 15-1 不会溢出 4 位系统的有符号数

5 - 0 = 0101 + 1111 + 1

    1
 0101
+1111
=====

11111
 0101
+1111
=====
 0101

所以 5 - 0 肯定执行 1,因为这是一个减法,不是溢出

15 - 1 = 1111 + ~1 带进位设置

    1
 1111
 1110
 ====

11111
 1111
 1110
 ====
 1110

如您所说,带 1 的减法不是无符号溢出

同样 -1 - 1 = 1111 + ~1 设置进位位

11111
 1111
 1110
 ====
 1110

最后一位进位是 1,进位是 1,它们匹配,没有符号溢出。

8 + 8 = 1000 + 1000,进位清晰

    0
 1000
+1000
=====

10000
 1000
+1000
=====
 0000

无符号溢出。

嗯 4 + 4

    0
 0100
+0100
=====

01000
 0100
+0100
=====
 1000

无符号添加进位为0 这不是无符号溢出。但这是一个有符号溢出,因为 msbit 的进位和进位不同。 +4 + +4 = +8,在4位有符号系统中你不能表示+8,所以有符号溢出是准确的。

无论有多少位,奇怪的数字都是 0 和 1,其余的都是 0,0 和 8 或 -8 用于 4 位系统。

用 2、3 或 4 位数字的所有组合制作图表,然后手动查看所有组合以查看它们是否有意义。无论你找到多少位宽,你找到的任何东西都会缩放,一个 100 位加法器就像一个 10 位加法器一样工作......

add           C V  unsigned    signed
00 + 00 = 000 0 0  0 + 0 = 0   0 +  0 =  0
00 + 01 = 001 0 0  0 + 1 = 1   0 +  1 =  1
00 + 10 = 010 0 0  0 + 2 = 2   0 + -2 = -2
00 + 11 = 011 0 0  0 + 3 = 3   0 + -1 = -1
01 + 00 = 001 0 0  1 + 0 = 1   1 +  0 =  1
01 + 01 = 010 0 1  1 + 1 = 2   1 +  1 =  2  signed cannot represent a +2
01 + 10 = 011 0 0  1 + 2 = 3   1 + -2 = -1
01 + 11 = 100 1 0  1 + 3 = 4   1 + -1 =  0  unsigned cannot represent +4
10 + 00 = 010 0 0  2 + 0 = 2  -2 +  0 = -2 
10 + 01 = 011 0 0  2 + 1 = 3  -2 +  1 = -1
10 + 10 = 100 1 1  2 + 2 = 4  -2 + -2 = -4 neither +4 nor -4 will fit in 2 bits
10 + 11 = 101 1 1  2 + 3 = 5  -2 + -1 = -3 neither +4 nor -3 will fit in 2 bits
11 + 00 = 011 0 0  3 + 0 = 3  -1 +  0 = -1 
11 + 01 = 100 1 0  3 + 1 = 4  -1 +  1 = -2 +4 does not fit in 2 bits
11 + 10 = 101 1 1  3 + 2 = 5  -1 + -2 = -3 neither +5 nor -3 fit in 2 bits
11 + 11 = 110 1 0  3 + 3 = 6  -1 + -1 = -2 6 does not fit in 2 bits
sub
00 - 00 = 100 0 0
00 - 01 = 011 1 0  0 - 1 = -1   -1 does not fit in an unsigned result
00 - 10 = 010 1 1  0 - 2 = -2  0 - -2 = +2  
00 - 11 = 001 1 0  0 - 3 = -3
01 - 00 = 101 0 0
01 - 01 = 100 0 0
01 - 10 = 011 1 1  1 - 2 = -1  1 - -2 =  3
01 - 11 = 010 1 1  1 - 3 = -2  1 - -1 =  2
10 - 00 = 110 0 0  
10 - 01 = 101 0 1             -2 -  1 = -3
10 - 10 = 100 0 0
10 - 11 = 011 1 0  2 - 3 = -1
11 - 00 = 111 0 0
11 - 01 = 110 0 0
11 - 10 = 101 0 0
11 - 11 = 100 0 0

生成上述代码的代码

printf("add\n");
for(ra=0;ra<4;ra++)
{
    for(rb=0;rb<4;rb++)
    {
        rd=(ra&1)+(rb&1);
        rc=ra+rb;
        rd=(rd>>1)&1;
        re=(rc>>2)&1;
        if(re) c=1; else c=0;
        if(rd!=re) v=1; else v=0;

        if(ra&2) printf("1"); else printf("0");
        if(ra&1) printf("1"); else printf("0");
        printf(" + ");
        if(rb&2) printf("1"); else printf("0");
        if(rb&1) printf("1"); else printf("0");
        printf(" = ");
        if(rc&4) printf("1"); else printf("0");
        if(rc&2) printf("1"); else printf("0");
        if(rc&1) printf("1"); else printf("0");
        printf(" %u %u\n",c,v);
    }
}
printf("sub\n");
for(ra=0;ra<4;ra++)
{
    for(rb=0;rb<4;rb++)
    {
        rd=(ra&1)+((~rb)&1)+1;
        rc=ra+((~rb)&3)+1;
        rd=(rd>>1)&1;
        re=(rc>>2)&1;
        if(re) c=0; else c=1;
        if(rd!=re) v=1; else v=0;

        if(ra&2) printf("1"); else printf("0");
        if(ra&1) printf("1"); else printf("0");
        printf(" - ");
        if(rb&2) printf("1"); else printf("0");
        if(rb&1) printf("1"); else printf("0");
        printf(" = ");
        if(rc&4) printf("1"); else printf("0");
        if(rc&2) printf("1"); else printf("0");
        if(rc&1) printf("1"); else printf("0");
        printf(" %u %u\n",c,v);
    }
}

现在你的问题是关于无符号数字是吗?所以你可能不关心 V 位或右半部分,即有符号的一半。

这是我实现的一个小型 16 位处理器的一些 HDL/RTL:

case 4b0000:
{
    //0000 add rd,rs
    op_a = bundle(1b0,reg[bundle(2b0,inst[4;8])].value);
    op_b = bundle(1b0,reg[bundle(2b0,inst[4;4])].value);
    op_res = op_a + op_b;
    reg[1].value[CBIT] <= op_res[16];
    reg[1].value[NBIT] <= op_res[15];

    if(op_res[16;0] == 16h0000)
    {
        reg[1].value[ZBIT] <= 1b1;
    }
    else
    {
        reg[1].value[ZBIT] <= 1b0;
    }
    if((op_a[15] == op_b[15]) && (op_res[15] != op_b[15] ) )
    {
        reg[1].value[VBIT] <= 1b1;
    }
    else
    {
            reg[1].value[VBIT] <= 1b0;
    }
    reg[bundle(2b0,inst[4;8])].value <= op_res[16;0];
}
case 4b0001:
{
    //0001 sub rd,rs
    op_a = bundle(1b0,reg[bundle(2b0,inst[4;8])].value);
    op_b = bundle(1b0,reg[bundle(2b0,inst[4;4])].value);
    op_res = op_a - op_b;
    reg[1].value[CBIT] <= (~op_res[16]);
    reg[1].value[NBIT] <= op_res[15];

    if(op_res[16;0] == 16h0000)
    {
        reg[1].value[ZBIT] <= 1b1;
    }
    else
    {
        reg[1].value[ZBIT] <= 1b0;
    }
    if((op_a[15] != op_b[15]) && (op_res[15] == op_b[15] ) )
    {
        reg[1].value[VBIT] <= 1b1;
    }
    else
    {
        reg[1].value[VBIT] <= 1b0;
    }
    reg[bundle(2b0,inst[4;8])].value <= op_res[16;0];
}

我已经/已经在其他逻辑中看到了带符号溢出的 msbit 事情,并且在尝试头对头分析中的所有可能组合时找不到它与进位与执行方法不匹配的情况。

如果我的答案太过分了,我不介意在开头剪掉它,因为它表明 5 - 0 有一个 1 作为 1 的进位,对于减法来说,这不是溢出。答案很长,因为您可能很难理解有符号与无符号以及加法器在逻辑中的一般工作方式。加法器不知道也不关心有符号或无符号,它确实关心加法与减法,用减法你反转第二个操作数,反转进位到 lsbit 和 msbit 的进位(想想加法,加法和进位, sub 和 sub 带进位)。签名与未签名会照顾自己(二进制补码的美丽)。将上述内容简化为仅无符号的讨论使其简单化了一半以上,因为有符号的溢出对于不经意的观察者来说并不明显(因为无符号溢出)。

我当然希望我剪切并粘贴已调试的 HDL,如果我不这样做会得到很多响应/更正...我花了几天时间说服自己以上所有内容,并与我拥有的其他处理器的结果进行比较访问等。希望这可以为您节省几天时间。

【讨论】:

  • 这实际上很有帮助。非常感谢!
【解决方案2】:

不是专家,但关于减法的整个陈述似乎是错误的。

您可以通过两种基本方式实现减法:直接作为减法,或作为二进制补码的加法。

如果您使用二进制补码加法,那么正如您所说:1 的进位是下溢。

5 - 6
= 0101 - 0110
= 0101 + (1001 + 1)
= 0101 + 1010
= (0)1111, carry 0 = underflow

如果直接相减,那么1进位就是下溢:

0101 - 0110:
0     to    1 is 1
1     to (1)0 is 1, carry 1
1 + 1 to (1)1 is 1, carry 1
0 + 1 to (1)0 is 1, carry 1 = underflow

【讨论】:

    【解决方案3】:

    可能还有其他等效的方法可以为加法器设计溢出检测单元,但最常见的是Cin XOR Cout。比如看第4讲的结尾http://cs.nyu.edu/~gottlieb/courses/2007-08-fall/arch/class-notes.html

    它只是检查被添加的数字(如果某些东西被反转为 2 的补码无关紧要,我们会在之后查看这些值)进入最后一位的计算,但不进入支持位之外的数字 -大小,或相反。

    这是有道理的,因为如果它们进位而不是进位,则结果必须为负(因为 MSB 必须为 1),但操作数必须为正(因为如果它们是负数,则会进位)。这就是溢出的定义,因为两个正数之和不能等于一个负数。

    这是一个签名模型,但我不确定这是否是您正在寻找的模型,因为您提到了未签名模型。如果是这样,那么你是对的,简单加法模型在执行为 1 时溢出(这相当于上面如果你认为加法每个操作数的 MSB 有一个额外的 0,那么执行将始终为 0,如果进位为 1,则溢出。在这种情况下,进位是我们模型中的进位。

    如果值为负,则减法会导致下溢。如果我们认为正操作数的附加 MSB 为 0,而负操作数的附加 MSB 为 1(符号扩展),我们可以再次得出等价。那么当结果的 MSB 为 1 时,我们是否定的。如果我们的原始模型中的进位(新模型中的进位)为 0,就会发生这种情况,因为只有这样,新模型中结果的 MSB 才会保持为 1 .

    您的示例也不例外:0101 + 1111 + 1 = 0101 进位为 1,因此没有下溢,因为结果是正数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-28
      • 2012-02-29
      • 2013-04-10
      • 1970-01-01
      • 2016-05-22
      • 1970-01-01
      • 2011-04-23
      相关资源
      最近更新 更多