Детали реализации оборудования с плавающей запятой

Я пытаюсь реализовать 32-разрядный аппаратный делитель с плавающей запятой в аппаратном обеспечении, и мне интересно, могу ли я получить какие-либо предложения относительно некоторых компромиссов между различными алгоритмами?

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

Когда-то очень давно я столкнулся с этим аккуратным и легким в использовании алгоритмом деления на плаву / фиксированную точку, используемым в военных FPU того периода:

  1. вход должен быть без знака и сдвинут так, что x < y и оба находятся в диапазоне < 0.5 ; 1 > < 0.5 ; 1 >

    не забудьте сохранить разницу сдвигов sh = shx - shy и оригинальные знаки

  2. найдем f (путем итерации), так что y*f -> 1 .... после этого x*f -> x/y который является результатом разделения

  3. (sig=sigx*sigy) x*f назад sh и восстановите знак результата (sig=sigx*sigy)

    x*f можно легко вычислить следующим образом:

     z=1-y (x*f)=(x/y)=x*(1+z)*(1+z^2)*(1+z^4)*(1+z^8)*(1+z^16)...(1+z^2n) 

    где

     n = log2(num of fractional bits for fixed point, or mantisa bit size for floating point) 

    Вы также можете остановиться, когда z^2n равно нулю на типах данных с фиксированной битовой шириной.

[Edit2] Было немного времени и настроение для этого, так вот 32-битная реализация IEEE 754 C ++

Я удалил старые (bignum) примеры, чтобы избежать путаницы для будущих читателей (они по-прежнему доступны в истории изменений, если это необходимо)

 //--------------------------------------------------------------------------- // IEEE 754 single masks const DWORD _f32_sig =0x80000000; // sign const DWORD _f32_exp =0x7F800000; // exponent const DWORD _f32_exp_sig=0x40000000; // exponent sign const DWORD _f32_exp_bia=0x3F800000; // exponent bias const DWORD _f32_exp_lsb=0x00800000; // exponent LSB const DWORD _f32_exp_pos= 23; // exponent LSB bit position const DWORD _f32_man =0x007FFFFF; // mantisa const DWORD _f32_man_msb=0x00400000; // mantisa MSB const DWORD _f32_man_bits= 23; // mantisa bits //--------------------------------------------------------------------------- float f32_div(float x,float y) { union _f32 // float bits access { float f; // 32bit floating point DWORD u; // 32 bit uint }; _f32 xx,yy,zz; int sh; DWORD zsig; float z; // result signum abs value xx.f=x; zsig =xx.u&_f32_sig; xx.u&=(0xFFFFFFFF^_f32_sig); yy.f=y; zsig^=yy.u&_f32_sig; yy.u&=(0xFFFFFFFF^_f32_sig); // initial exponent difference sh and normalize exponents to speed up shift in range sh =0; sh-=((xx.u&_f32_exp)>>_f32_exp_pos)-(_f32_exp_bia>>_f32_exp_pos); xx.u&=(0xFFFFFFFF^_f32_exp); xx.u|=_f32_exp_bia; sh+=((yy.u&_f32_exp)>>_f32_exp_pos)-(_f32_exp_bia>>_f32_exp_pos); yy.u&=(0xFFFFFFFF^_f32_exp); yy.u|=_f32_exp_bia; // shift input in range while (xx.f> 1.0f) { xx.f*=0.5f; sh--; } while (xx.f< 0.5f) { xx.f*=2.0f; sh++; } while (yy.f> 1.0f) { yy.f*=0.5f; sh++; } while (yy.f< 0.5f) { yy.f*=2.0f; sh--; } while (xx.f<=yy.f) { yy.f*=0.5f; sh++; } // divider block z=(1.0f-yy.f); zz.f=xx.f*(1.0f+z); for (;;) { z*=z; if (z==0.0f) break; zz.f*=(1.0f+z); } // shift result back for (;sh>0;) { sh--; zz.f*=0.5f; } for (;sh<0;) { sh++; zz.f*=2.0f; } // set signum zz.u&=(0xFFFFFFFF^_f32_sig); zz.u|=zsig; return zz.f; } //--------------------------------------------------------------------------- 

Я хотел сохранить его простым, так что он еще не оптимизирован. Вы можете, например, заменить все *=0.5 и *=2.0 на показатель inc/dec ... Если вы сравниваете результаты FPU с оператором float / это будет немного менее точным, потому что большинство FPU вычисляют в 80-битном внутреннем формате и эту реализацию только на 32 бита.

Как вы можете видеть, я использую из FPU только +,-,* . Материал может быть ускорен с использованием быстрых алгоритмов sqr, таких как

  • Быстрое вычисление квадратов бигума

особенно если вы хотите использовать большие битовые ширины ...

Не забудьте выполнить нормализацию и / или переполнение / исправление нижнего streamа.

  • Почему Double.MIN_VALUE не является отрицательным?
  • Преобразование float в строку
  • Почему я не могу использовать значение float в качестве параметра шаблона?
  • Double vs float на iPhone
  • Что означают F и D в конце числовых литералов?
  • Как вы объедините число с плавающей запятой в Perl?
  • Как сравнить два числа с плавающей запятой в Bash?
  • Операции с плавающей запятой в C-ассоциативном?
  • Проблемы сравнения с плавающей запятой MySQL
  • pow (), кажется, отсутствует здесь
  • Как я могу написать функцию питания самостоятельно?
  • Interesting Posts

    В C # проверьте, что имя файла * возможно * действительное (не то, что оно существует)

    Команда для обмена одной и той же папкой с несколькими именами

    Должен ли я всегда возвращать IEnumerable вместо IList ?

    Доступ к удаленной базе данных mysql из командной строки

    Сделать среднюю кнопку мыши вести себя как двойной щелчок в Windows 7?

    SSH по-прежнему запрашивает пароль после настройки проверки подлинности на основе ключа

    Является ли обратная косая черта приемлемой в директивах C и C ++ #include?

    break и label: «Отсутствует метка MyLabel»

    Могу ли я скомпилировать все .cpp-файлы в src / to .o в obj /, затем ссылку на двоичный файл ./?

    Разница между функциями $ (window) .load () и $ (document) .ready ()

    Как работает Skype без переадресации портов?

    Установите спящий раздел Windows

    SelectListItem с атрибутами данных

    Как вручную включить внешний пакет aar с помощью новой системы сборки Gradle Android

    Преобразование SVG в PDF

    Давайте будем гением компьютера.