Реализация вычитания с плавающей запятой - PullRequest
4 голосов
/ 26 февраля 2009

все, что я пытаюсь реализовать арифметическую библиотеку с плавающей запятой, и у меня проблемы с пониманием алгоритма вычитания чисел с плавающей запятой. Я успешно реализовал сложение, и я подумал, что вычитание было лишь частным случаем, но, похоже, я где-то ошибаюсь. Я добавляю код здесь только для справки, он имеет много самоочевидных функций, но я не ожидаю, что кто-то поймет его на 100%. В чем я хотел бы помочь, так это в алгоритме. Мы следуем тому же методу, что и при добавлении чисел с плавающей точкой, за исключением того, что, когда мы добавляем мантиссы, мы конвертируем отрицательный (тот, который мы вычитаем) в дополнение к двум, а затем добавляем их?

Я так и делаю, но результат неверен. Хотя это очень близко ... но не то же самое. У кого-нибудь есть идеи? Заранее спасибо!

Я совершенно уверен, что способ, которым я делаю вещи, работает, так как я реализовал почти идентичный алгоритм добавления поплавков, и он работает как шарм.

_float subFloat(_float f1,_float f2)
{
unsigned char diff;
_float result;

//first see whose exponent is greater
if(f1.float_parts.exponent > f2.float_parts.exponent)
{
    diff = f1.float_parts.exponent - f2.float_parts.exponent;

    //now shift f2's mantissa by the difference of their exponent to the right
    //adding the hidden bit
    f2.float_parts.mantissa = ((f2.float_parts.mantissa)>>1) | (0x01<<22);
    f2.float_parts.mantissa >>= (int)(diff);//was (diff-1)

    //also increase its exponent by the difference shifted
    f2.float_parts.exponent = f2.float_parts.exponent + diff;
}
else if(f1.float_parts.exponent < f2.float_parts.exponent)
{
    diff = f2.float_parts.exponent - f1.float_parts.exponent;
    result = f1;
    f1 = f2;        //swap them
    f2 = result;

    //now shift f2's mantissa by the difference of their exponent to the right
    //adding the hidden bit
    f2.float_parts.mantissa = ((f2.float_parts.mantissa)>>1) | (0x01<<22);
    f2.float_parts.mantissa >>= (int)(diff);

    //also increase its exponent by the difference shifted
    f2.float_parts.exponent = f2.float_parts.exponent + diff;
}
else//if the exponents were equal
  f2.float_parts.mantissa = ((f2.float_parts.mantissa)>>1) | (0x01<<22); //bring out the hidden bit




//getting two's complement of f2 mantissa
f2.float_parts.mantissa ^= 0x7FFFFF;
f2.float_parts.mantissa += 0x01;



result.float_parts.exponent = f1.float_parts.exponent;
result.float_parts.mantissa = (f1.float_parts.mantissa +f2.float_parts.mantissa)>>1;
                                                //gotta shift right by overflow bits

//normalization
if(manBitSet(result,1))
    result.float_parts.mantissa <<= 1;  //hide the hidden bit
else
    result.float_parts.exponent +=1;

return result;

}

Ответы [ 2 ]

2 голосов
/ 26 февраля 2009

a-b == a+(-b), и унарный минус тривиален, так что я бы даже не стал беспокоиться о двоичном минусе.

1 голос
/ 26 февраля 2009

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

Нужно ли дополнять и дополнять два, а не вычитать?

Если это не проблема, у меня проблемы с вашим алгоритмом. Я давно не делал ничего подобного. Не могли бы вы предоставить некоторые детали? Более конкретно, что такое скрытый бит?

Мне кажется, что обработка скрытого бита подходит для сложения, но не для вычитания. Может быть, вы должны установить его в мантиссе f1, а не в f2? Или отрицать мантиссу f1 вместо f2?

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

Редактировать: ОК, я посмотрел ссылки в вашем комментарии. Одна вещь, которую вы не можете сделать в предоставленном коде - это нормализация. При добавлении либо скрытые биты переполняются (смещение мантиссы влево, приращение показателя степени), либо нет. При вычитании произвольные части мантиссы могут быть равны нулю. В десятичном числе рассмотрите добавление 0.5E1 и 0.50001E1; вы получите 1.00001E1, и если вы нормализуетесь, вы получите 0.10001E2. Вычитая 0,5E1 из 0,50001E1, вы получаете 0,00001E1. Затем вам нужно сместить мантиссу влево и уменьшить показатель степени на столько, сколько потребуется, чтобы получить 0.1E-4.

...