целочисленное вычитание двойной точности с 32-разрядными регистрами (MIPS) - PullRequest
2 голосов
/ 15 октября 2010

Я изучаю компьютерную арифметику. Книга, которую я использую (Паттерсон и Хеннесси), перечисляет следующий вопрос.

Напишите код mips для проведения двойного точное целочисленное вычитание для 64-битные данные. Предположим, первый операнд быть в регистрах $ t4 (привет) и $ t5 (lo), второе место в $ t6 (hi) и $ T7 (ло).

Мое решение для ответа

sub  $t3, $t5, $t7   # Subtract lo parts of operands. t3 = t5 - t7
sltu $t2, $t5, $t7   # If the lo part of the 1st operand is less than the 2nd,
                     #   it means a borrow must be made from the hi part
add  $t6, $t6, $t2   # Simulate the borrow of the msb-of-low from lsb-of-high
sub  $t2, $t4, $t6   # Subtract the hi's. t2 = t4 - t6

Однако, автор дал решения этой проблемы, как показано ниже

Для целых чисел двойной точности со знаком,

subu $t3, $t5, $t7   
sltu $t2, $t5, $t7  
add  $t6, $t6, $t2
sub  $t2, $t4, $t6

Для целых чисел двойной точности без знака,

subu $t3, $t5, $t7   
sltu $t2, $t5, $t7  
addu $t6, $t6, $t2
subu $t2, $t4, $t6

Мое понимание различия в работе sub/add и subu/addu заключается в том, что исключение переполнения генерируется в sub/add, а не в subu/addu. И sub/add, и subu/addu вычитают / складывают биты операндов, и интерпретация операндов, подписанных или неподписанных, не имеет значения для результата в отличие от slt и sltu инструкций.

Вопрос 1
На основании предоставленных автором решений я делаю вывод, что обнаружение переполнения обрабатывается, тогда как в своем решении я не думал об этом. Я прав? Есть ли еще что-то, чего мне не хватает?

Вопрос 2
Если предположить, что мой вывод верен, почему обнаружение переполнения отключено для предоставленных автором решений в случае вычитания беззнаковой двойной точности с использованием addu и subu?

1 Ответ

6 голосов
/ 27 октября 2010

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

Например, рассмотрим 8-битные последовательности (MIPS имеет 32-битные регистры, но для моих примеров 8-битные проще). Предположим, что беззнаковая интерпретация: 8-битная последовательность представляет числовое значение от 0 до 255 (включительно). Если я добавлю 10010011 (числовое значение 147) к 01110110 (числовое значение 118), я получу 00001001 (числовое значение 9). 9 не равно 147 + 118. Я получаю этот результат, потому что математическое значение равно 265, что не может вместиться в 8 бит. Результат сложения потребовал бы 9 битов, но верхний девятый бит был отброшен.

Теперь представьте тот же пример с подписанным толкованием. 10010011 теперь имеет числовое значение -109. 01110110 по-прежнему имеет числовое значение 118, а полученный результат (00001001) имеет значение 9. Математическая сумма -109 и 118 равна 9, поэтому переполнения нет.

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

Архитектура MIPS предоставляет средства для запуска исключений при переполнении. Концептуально, существует три возможных операций сложения над 32-битными словами:

  • дополнение, которое молча игнорирует переполнения (результат усекается)
  • добавление, которое вызывает исключение при переполнении со знаком (переполнение происходит, если входная и выходная последовательности интерпретируются как числа со знаком)
  • добавление, которое вызывает исключение при переполнении без знака (переполнение, если входная и выходная последовательности интерпретируются как числа без знака)

MIPS реализует первые два вида дополнений, соответственно с кодами операций addu и add. В документации MIPS они называются соответственно без знака и со знаком арифметики . Не существует кода операции для вызова исключений при переполнении без знака. На практике компиляторы C используют только addu, но они могут использовать add для подписанных типов (это разрешено стандартом C, но может привести к поломке огромного количества существующего кода). Компиляторы Ada используют add, потому что Ada делает проверку переполнения обязательной.

Как говорится ...

Паттерсон и Хеннесси хотят реализовать арифметику со знаком и без знака на 64-битных целых числах. Для арифметики без знака они не хотят никаких исключений, поэтому они используют addu и subu. Для арифметики со знаком они хотят, чтобы произошло исключение, когда математический результат не уместился бы в 64-битную последовательность со знаковой интерпретацией. Они не хотят вызывать исключение из-за некоторого ложного переполнения при обработке младших 32-битных половин. Вот почему они используют subu для низких частей.

Ваше решение неверно, потому что оно может вызвать исключение, если оно не должно. Предположим, что вы хотите вычесть 2000000000 (два миллиарда) из -2000000000 (минус два миллиарда). Математический результат - 4000000000 (четыре миллиарда). Два операнда и результат определенно помещаются в 64 бита (представляемый диапазон от -9223372036854775808 до 9223372036854775807). Следовательно, для 64-битной знаковой арифметики переполнения нет: не должно быть исключений. Однако в этой ситуации ваш первый sub сообщит о переполнении. Это sub работает с 32-битными значениями и 32-битной арифметикой со знаком. Его операнды будут 01110111001101011001010000000000 и 10001000110010100110110000000000. Обратите внимание, что оба эти значения умещаются в 32 бита: 32-разрядная интерпретация этих значений со знаком соответственно равна плюс и минус два миллиарда. Результат вычитания, однако, составляет четыре миллиарда, и он не умещается в 32 бита (как число со знаком). Таким образом, ваш sub вызывает исключение.

Как правило, обнаружение переполнения связано с выполнением действий, которые зависят от интерпретации подписи, что влияет на обработку наиболее значимого бита. Для большой целочисленной арифметики все слова, кроме самого значимого, должны рассматриваться как беззнаковые, следовательно, addu / subu везде. В качестве первого шага все будет проще понять, если вы сначала сконцентрируетесь на беззнаковой арифметике, без исключения (тогда вы просто используете addu и subu и никогда add или sub) .

...