MIPS — как преобразовать набор целых чисел в числа с плавающей запятой одинарной точности

Мне действительно трудно понять, как подойти к этой проблеме. Я понимаю, что хочу взять двоичное представление как целого числа, так и дроби, объединить их для получения мантиссы и присвоить знаковый бит началу, но я не знаю, как на самом деле реализовать это в MIPS.

Может ли кто-нибудь помочь мне хотя бы начать?

Предположим, что ваше оборудование MIPS не имеет регистров с плавающей запятой и ALU с плавающей запятой. Если вы хотите выполнить сложение с плавающей запятой, вам придется использовать целочисленные инструкции MIPS, которые используют целочисленные регистры ($0 - $31) и целочисленное ALU для выполнения работы. В этом задании вы будете писать код MIPS, используя только целочисленные инструкции и целочисленные регистры, для реализации процедуры сложения двух чисел с плавающей запятой и написания основной функции для вызова процедуры.

  1. Напишите процедуру MIPS toFloat для перевода числа с плавающей запятой в формат одинарной точности IEEE. В качестве входных данных процедура принимает три целых числа: $a0, $a1, $a2, которые представляют число с плавающей запятой следующим образом: если $a0 содержит 0, число с плавающей запятой положительно, иначе, если $a0 содержит 1, число с плавающей запятой отрицательное. Число, хранящееся в регистре $a1, представляет собой целую часть числа с плавающей запятой, а число, хранящееся в регистре $a2, представляет собой дробную часть числа с плавающей запятой. Например, чтобы представить число с плавающей запятой -5,25, три входных регистра должны содержать следующие числа: $a0 = 1, $a1 = 5 и $a2 = 25. Для дробной части вы можете использовать div rt инструкция для деления 25 на 100. Дробь будет храниться в регистре HI, и вы можете использовать команду mfhi для извлечения дроби. Процедура вернет v0, который содержит шаблон одинарной точности IEEE, соответствующий числу с плавающей запятой, представленному тремя входными числами. Когда у вас есть эта процедура, вы можете использовать ее для преобразования входных чисел 2.5 и 7.5 в их формат одинарной точности IEEE.

  2. Напишите процедуру MIPS printFloat для печати числа в формате одинарной точности IEEE. Ввод процедуры находится в $a0, который является числом в формате одинарной точности IEEE. Процедура просто напечатает битовую комбинацию, хранящуюся в $a0. Вы можете использовать цикл для печати каждого бита. Если у вас есть эта процедура, вы можете использовать ее для печати входных чисел 2,5 и 7,5 в их формате с плавающей запятой.

  3. #P6#
    #P7# #P8# #P9# #P10#

Вот код, который у меня есть на данный момент:

http://s7.postimg.org/v39ufikaj/code.png


person Nimbus    schedule 21.10.2013    source источник
comment
Как далеко назад просто помочь мне начать идти? Могу ли я предложить использовать sll $t0, $a0, 31, чтобы переместить бит знака в нужное место, или $t1, $t1, $t0 - или вам нужен ответ на что-то более похожее на то, что такое сдвиг влево и побитовое или?   -  person RobertB    schedule 21.10.2013
comment
Это определенно помогает. Таким образом, очевидно, что мы помещаем бит знака в первую позицию, сдвигая его, но я немного смущен тем, как я определяю экспоненту и мантиссу из этих значений.   -  person Nimbus    schedule 21.10.2013
comment
Что касается фрагмента кода, вам, вероятно, больше повезет, отправив его на gist.github.com — читая ассемблерный код из изображение .png слишком болезненно!   -  person RobertB    schedule 22.10.2013


Ответы (1)


Хорошо, первый шаг (как отмечено в комментариях) — потратить некоторое время на конвертер, который показывает биты, например, здесь: binaryconvert.com конвертер с плавающей запятой.

Затем самое простое — взять $a0 и сбросить бит 0 в бит 1 нашего результата. Что-то типа:

add $v0, $zero, $zero # initialize our result
sll $t0, $a0, 31 # shift the lsb to the msb
or $v0, $v0, $t0 # set the sign bit in the result

Но теперь нам нужно заняться математикой. Я надеялся, что $a1 будет частью целого числа, а $a2 будет двоичной дробной частью. Но это не так... они говорят, что $a1 — это целое число (все еще целое число в двоичном формате), но $a2 — это, по сути, центы. (Если 25/100 = 0,25 десятичного числа, то $a2 содержит центы.)

Вот я и сам запутался. В инструкции сказано: «Используйте команду div rs rt, чтобы разделить 25 на 100. Дробь будет сохранена в регистре HI». Но когда я прочитал, что делает div (Справочник инструкций MIPS ), он говорит, что помещает частное в $LO, а остаток в $HI. Таким образом, деление 25 на 100 даст вам... 25. Это хороший способ отбросить количество, превышающее 100, но он не приводит нас к двоично-дробному представлению числа.

На самом деле, я только что провел целый урок плюс обед, пытаясь найти элегантный способ взять число от 0 до 99, разделить его на 100 и преобразовать результат в двоичный вид без использования FPU. Я опаздываю. Так что я позволю вам спросить профессора об этой части.

Но как только у нас есть целая часть числа в $a1 и строка из 1 и 0, представляющая дробную часть (давайте поместим это в $s2), нам просто нужно ее нормализовать. У нас есть число в формате $a1.$s2, и нам нужно, чтобы оно было в таком формате:

1.nnnnnnn

... где мы начинаем с 1, а затем дробная часть состоит из любого количества двоичных цифр.

Вот некоторый псевдокод, который может сработать.

  • Сдвигайте $a1 влево до тех пор, пока старший бит не станет равным «1». Сохраните количество смен в $t0. (Примечание: предполагается, что целая часть не равна нулю)
  • (31 - $t0) дает вам показатель степени. Отрегулируйте его с помощью смещения и заполните биты 30-23 вашего результата с плавающей запятой.
  • $t0 также сообщает вам, сколько места у вас есть для дробных битов. Сдвиньте $s2 на соответствующую величину (которая зависит от того, как он закодирован) и or так, чтобы он заполнил младшие значащие биты $a1
  • Сдвиг $a1 оставил еще один бит, потому что ведущая «1» отбрасывается в IEEE FP.
  • Вставьте верхние 23 бита $a1 в биты 22-0 результата с плавающей запятой.

Давайте посмотрим, работает ли это на примере. $a1 имеет целочисленную часть 0x0000C000, а $s2 каким-то образом был загружен 0,75 (1 x 2^-1 + 1 x 2^-2)

$a1: 0000 0000 0000 0000 1100 0000 0000 0000 
$s2: 1100 0000 0000 0000 0000 0000 0000 0000

Мне нужно сдвинуть $a1 16 раз:

$a1: 1100 0000 0000 0000 0000 0000 0000 0000 

Это должно дать мне показатель степени 31 - 16 = 15. Добавьте смещение 127, и я получу 142 (0x8E). Это идет в разделе экспоненты.

Мне нужно сдвинуть $s2 вправо на ту же величину (16):

$s2: 0000 0000 0000 0000 1100 0000 0000 0000

or вместе:

$a1:  1100 0000 0000 0000 1100 0000 0000 0000

Визуализируйте это с десятичной точкой:

original:  1100 0000 0000 0000.1100 0000 0000 0000
normaliz: 1.100 0000 0000 0000 1100 0000 0000 0000

Поскольку мы опускаем подразумеваемую «1» слева от десятичной точки, сдвинем ее, и мы получим:

$a1:  100 0000 0000 0000 1100 0000 0000 0000 0

Возьмите 23 бита этого. Итак, если я правильно понял, этот преобразователь выше должен сказать, что 49152.75 хранится в IEEE FP как:

01000111 01000000 00000000 11000000

Знак = 0

Показатель = 10001110 (0x8E)

Мантисса = 1000 0000 0000 0001 1000 000

(Теперь попробуйте представить мое удивление, что это действительно сработало!)

person RobertB    schedule 22.10.2013