Реализация вычитания с плавающей запятой

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

Решение

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

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

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

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

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

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

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