Эмуляция "double" с использованием 2 "float" s

Я пишу программу для встроенного оборудования, которое поддерживает только 32-разрядную арифметику с плавающей запятой с одинарной точностью. Однако алгоритм, который я реализую, требует 64-битного сложения и сравнения с двойной точностью. Я пытаюсь подражать типу double datatype, используя кортеж из двух float s. Таким образом, double d будет эмулироваться как struct, содержащий кортеж: (float d.hi, float d.low).

Сравнение должно быть простым, используя лексикографическое упорядочение. Однако добавление немного сложно, потому что я не уверен, какую базу я должен использовать. Должно ли это быть FLT_MAX? И как я могу обнаружить перенос?

Как это можно сделать?


Изменить (Ясность): мне нужны дополнительные значащие цифры, а не дополнительный диапазон.

Ответ 1

double-float - это метод, который использует пары чисел с одной точностью, чтобы добиться почти в два раза точности арифметики с одной точностью, сопровождаемой небольшим уменьшением диапазона экспоненциальной точности (из-за промежуточного переполнения и переполнения на дальних концах диапазон). Основные алгоритмы были разработаны T.J. Деккер и Уильям Кахан в 1970-х годах. Ниже я перечисляю два довольно недавних документа, которые показывают, как эти методы могут быть адаптированы к графическим процессорам, однако большая часть материалов, охватываемых этими документами, применима независимо от платформы, поэтому должна быть полезна для этой задачи.

http://hal.archives-ouvertes.fr/docs/00/06/33/56/PDF/float-float.pdf Гийом Да Граса, Дэвид Дефур Реализация операторов float-float на графическом оборудовании, 7-я конференция по реальным цифрам и компьютерам, RNC7.

http://andrewthall.org/papers/df64_qf128.pdf Эндрю Таль Расширенные значения чисел с плавающей запятой для вычисления графического процессора.

Ответ 2

Это не будет простым.

Поплавок (одиночная точность IEEE 754) имеет 1 знаковый бит, 8 битов экспоненты и 23 бита мантиссы (ну, эффективно 24).

Двойная (двойная точность IEEE 754) имеет 1 знаковый бит, 11 битов экспоненты и 52 бит мантиссы (эффективно 53).

Вы можете использовать бит знака и 8 битов экспоненты из одного из ваших поплавков, но как вы собираетесь получить еще 3 экспоненциальных бита и 29 бит мантиссы из другого?

Возможно, кто-то еще может придумать что-то умное, но мой ответ "это невозможно". (Или, по крайней мере, "не проще, чем использовать 64-битную структуру и реализовать свои собственные операции" )

Ответ 3

Это зависит от того, какие типы операций вы хотите выполнить. Если вы только заботитесь о дополнениях и вычитаниях, Kahan Summation может стать отличным решением.

Ответ 4

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

(Для добавления основной принцип состоит в том, чтобы разбить представление (например, 64 бита) каждого значения на три его составляющие - знак, показатель и мантисса, а затем сдвинуть мантиссу одной части на разницу в показателях, добавить или вычесть из мантиссы другой части на основе знаковых бит и, возможно, перенормировать результат, сдвинув мантиссу и соответствующим образом отрегулировав показатель. Вдобавок, есть множество подробных подробностей для учета, чтобы избегать ненужной потери точности и иметь дело со специальными значениями, такими как бесконечности, NaNs и денормализованные номера.)

Ответ 5

Это непрактично. Если это так, каждый встроенный 32-битный процессор (или компилятор) будет эмулировать двойную точность, делая это. Как бы то ни было, никто этого не знает. Большинство из них просто заменяют float для double.

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

Ответ 6

Учитывая все ограничения для высокой точности над 23 величинами, я думаю, что наиболее плодотворным методом было бы реализовать пользовательский арифметический пакет.

Быстрый опрос показывает, что библиотека Double-Double С++ от Briggs должна отвечать вашим потребностям, а затем некоторым. См. this. [*] Реализация по умолчанию основана на double для достижения 30 значительных вычислений фигур, но их можно легко переписать для использования float для достижения 13 или 14 значимых цифр. Этого может быть достаточно для ваших требований, если будет предпринята осторожность для разделения операций добавления с одинаковыми значениями величины, добавив только крайности в последние операции.

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


[*] Источник С++ связан этой статьей, но только gzipped tar не является мертвой ссылкой.

Ответ 7

Другое программное решение, которое может быть полезным: GNU MPFR
Он заботится о многих других специальных случаях и позволяет произвольную точность (лучше, чем 64-битный двойной), что вам придется позаботиться о себе.

Ответ 8

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

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

Если вам действительно нужна длинная мантисса, попробуйте использовать пользовательскую библиотеку с плавающей запятой. Вы можете выбрать все, что вам достаточно, например, изменить библиотеку, чтобы адаптировать новый 48-битовый тип float, если требуется только 40 бит мантиссы и 7 бит экспоненты. Нет необходимости тратить время на вычисление/хранение ненужного 16 бит. Но эта библиотека должна быть очень эффективной, поскольку библиотеки компиляторов часто имеют оптимизацию уровня сборки для своего собственного типа float.