Переполнение/незаполнение в числах без знака

Итак, если у вас есть перенос 1 при сложении с числами без знака, у вас переполнение, а если у вас есть перенос 0 при вычитании, у вас недополнение. Но работает ли это во всех случаях?

Если вы делаете 5-0: 0101 -0000

= 0101 +(1111 + 1)

= 0101 +0000

= 0101... здесь перенос нуля вместо 1. Как объяснить этот случай? Есть ли другой способ сделать это?

(используя архитектуру MIPS или что-то еще)

---Редактировать

Спасибо Амадан. Хотя я понимаю эту часть. Моя проблема в том, что ноль кажется особым случаем. Кажется, это не соответствует тому, что делают обычные числа: в моем примере выше нет переноса 1.

В данный момент я разрабатываю схему, работаю с ALU и пытаюсь реализовать обнаружение переполнения, когда возник этот случай, который не следует тому, что делают другие.

Мы предполагаем, что при вычитании второй операнд предварительно инвертируется (дополнение до двух) перед входом в АЛУ (затем добавляется к первому операнду). Таким образом, всякий раз, когда «invert_b» для вычитания устанавливается равным 1, b инвертируется, и мы предполагаем, что проверяемый нами случай — это вычитание, которое должно иметь перенос, равный 1.


person Risshuu    schedule 21.10.2011    source источник
comment
Я не понимаю вопроса. Добавление положительного и отрицательного числа никогда не может привести к недополнению/переполнению.   -  person davin    schedule 21.10.2011
comment
Добавил немного больше информации .. надеюсь, это прояснит это.   -  person Risshuu    schedule 21.10.2011
comment
Что сказал @davin. Я не знаю, как они это делают в процессорах, но инвертирование нуля всегда должно давать вам перенос (1111 + 1 = (1)0000), таким образом говоря, что -0 = 0 не совсем правильно, если вы используете двойки. дополнение для целей вычитания.   -  person Amadan    schedule 21.10.2011
comment
Но если мы преобразуем в дополнение до двух перед выполнением вычитания, 0 снова будет просто 0000 ... а затем мы добавим после этого, и, поскольку схема думает, что мы вычитаем, она будет искать переполнение, если нет переноса ... вот где я я в замешательстве. Я надеюсь, что я не пропускаю то, что вы, ребята, уже упомянули.   -  person Risshuu    schedule 21.10.2011
comment
@Risshuu, это снова не просто 0000. Вычитание заставляет сумматор добавить исходное число и 1111+1, что равно 0000 с переносом 1, поэтому перенос противоположен обычному случаю добавления 0000. Следовательно, результат противоположен, что имеет смысл, потому что тогда будет потеря значимости, если и только если будет переполнение в случае +0. Поскольку в исходном случае +0 не может быть переноса 1, переполнения не будет, и по симметрии случай +0000 с переносом 1 всегда будет нести 1 и, следовательно, никогда не потеряет значение.   -  person davin    schedule 21.10.2011


Ответы (3)


Я считаю, что 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

unsigned add выполнение равно 0, это не беззнаковое переполнение. но это переполнение со знаком, потому что перенос в msbit и выполнение отличаются. +4 + +4 = +8, в 4-битной системе со знаком вы не можете представить +8, поэтому переполнение со знаком является точным.

Независимо от того, сколько битов, странные числа - это все нули и единица, а остальные нули, 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, ни о правой половине, подписанной половине.

Вот немного HDL/RTL для небольшого 16-битного процессора, который я реализовал:

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 (подумайте о добавлении, добавлении с переносом , саб и саб с переносом). Подписанный и неподписанный позаботится о себе (красота дополнения до двух). Сведение вышеизложенного к обсуждению только без знака делает его более чем наполовину простым, поскольку переполнение со знаком не (так) очевидно (как переполнение без знака) для случайного наблюдателя.

Я очень надеюсь, что я вырезал и вставил отлаженный HDL, получу много ответов/исправлений, если я этого не сделал... Я провел несколько дней, убеждая себя во всем вышеперечисленном и сравнивая с результатами других процессоров, к которым у меня был доступ, и т. д. Надеюсь, это сэкономит вам несколько дней.

person old_timer    schedule 22.10.2011
comment
Это очень помогает на самом деле. Большое спасибо! - person Risshuu; 23.10.2011

Не эксперт, но все утверждение о вычитании кажется неверным.

Вычитание можно реализовать двумя основными способами: непосредственно как вычитание или как сложение с дополнением до двух.

Если вы идете с добавлением двух дополнений, то, как вы говорите: перенос 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
person Amadan    schedule 21.10.2011

Могут быть и другие эквивалентные способы проектирования блоков обнаружения переполнения для сумматоров, но наиболее распространенным является Cin XOR Cout. Например, см. конец лекции 4 http://cs.nyu.edu/~gottlieb/courses/2007-08-fall/arch/class-notes.html

Он просто проверяет, учитываются ли добавляемые числа (если что-то инвертируется для дополнения до 2 или нет, мы смотрим на эти значения позже) в расчет последней цифры, но не в цифру за пределами поддерживаемого битового размера, или противоположный.

Это имеет смысл, потому что если они переносятся, а не выводятся, результат должен быть отрицательным (поскольку старший бит должен быть равен 1), но операнды должны быть положительными (поскольку, если бы они были отрицательными, было бы выполнено). Это определение переполнения, поскольку два плюса не могут в сумме давать минус.

Однако это подписанная модель, я не уверен, что это то, что вы ищете, поскольку вы упомянули неподписанную. Если это так, то вы правы, модель простого сложения имеет переполнение, когда выполнение равно 1 (это эквивалентно приведенному выше, если вы считаете, что сложение имеет дополнительный 0 для каждого старшего бита операнда, тогда выполнение будет всегда будет 0, и есть переполнение, если и только если перенос равен 1. В этом случае перенос является переносом в нашей модели).

Вычитание приводит к потере значимости, если значение отрицательное. Мы снова можем вывести эквивалентность, если посчитаем, что положительный операнд имеет добавленный старший разряд, равный 0, а отрицательный операнд равен единице (расширение знака). Тогда мы отрицательны, когда старший бит результата равен 1. Это происходит тогда и только тогда, когда перенос в нашей исходной модели (перенос в новой модели) равен 0, поскольку только тогда старший бит результата в новой модели останется равным 1. .

Ваш пример не исключение: 0101 + 1111 + 1 = 0101 с переносом 1, а значит нет потери памяти, так как результат положительный.

person davin    schedule 21.10.2011