Написание функции умножения с плавающей точкой на C - PullRequest
3 голосов
/ 15 марта 2012

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

float multiply(float foo, float bar);

Мне запрещено использовать любые библиотеки или любые операции с плавающей запятой, кроме оператора присваивания =

Я понимаю, как с плавающей точкой представлены в C, и я извлек показатели и дроби, выполнив это:

union sp_item { float frep; unsigned irep; };
union sp_item num;
num.frep = foo;
int exponent = ((num.irep >> 23) - 0x7f);
int frac = (num.irep << 9);

Я понимаю, что мне нужно добавить показатели (достаточно просто) и умножить две дроби. Дело в том, что я понятия не имею, с чего начать умножать дроби. Я думал о преобразовании дроби в ее шестнадцатеричное представление в виде строки (например, 0.5 будет «80000000») и написание алгоритма для умножения битов таким образом, но так как я не могу использовать ни одну из библиотек C, которые у меня есть Понятия не имею, как бы я поступил так. Может ли кто-нибудь указать мне правильное направление?

Редактировать: Мне пришло в голову, что плавающие могут быть представлены не во всех системах одинаково. В этом курсе мы предполагаем, что первый бит - это знак, следующие 8 бит - это показатель степени, а последние 23 бита - это дробь.

Редактировать: Это то, что я получил до сих пор. Когда я пытаюсь умножить два целых числа, я просто получаю ноль, если я не введу (long long)((long long)xRep * (long long)yRep) в мой список наблюдения отладчиков

#include <stdio.h>
union sp_item
{
  float frep;
  unsigned irep;
};

int main() {
float x = 0.25;
float y = 0.5;
union sp_item xUnion;
union sp_item yUnion;
xUnion.frep = x; yUnion.frep = y;

unsigned xExp = (xUnion.irep >> 23) - 0x7f;
unsigned yExp = (yUnion.irep >> 23) - 0x7f;

unsigned xRep = (xUnion.irep << 9);
unsigned yRep = (yUnion.irep << 9);


xRep = (xRep >> 1) | 0x80000000;
yRep = (yRep >> 1) | 0x80000000;

long long final = (long long)((long long)xRep * (long long)yRep);

printf("iRep: %x * 2^%d\n", xRep, xExp);
printf("iRep: %x * 2^%d\n", yRep, yExp);
printf("%01611x\n", final);
}

Ответы [ 3 ]

1 голос
/ 15 марта 2012

Почему бы просто не умножить дроби (извлеченные в их представление int), используя оператор умножения целых чисел, *?

0 голосов
/ 15 марта 2012

http://en.wikipedia.org/wiki/Floating_point может быть полезным чтением. Мантисса может иметь только определенный диапазон, и вам нужно будет откорректировать показатель степени, чтобы учесть это

0 голосов
/ 15 марта 2012

24 + 24 <64, поэтому вы можете использовать <code>long long умножение. Длинные длинные гарантированно будут достаточно большими, чтобы содержать числа от - (2 ^ 63-1) до (2 ^ 63-1)

Или вы можете разделить число на две части (16 бит младшего разряда + 8 бит старшего разряда) и использовать 32-битное умножение (обратите внимание, что unsigned long гарантированно предоставит не менее 32 бит).

Позаботьтесь о правильной нормализации результата впоследствии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...