Эмулируйте "double", используя 2 "float" s - PullRequest
57 голосов
/ 21 июля 2011

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

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

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


Редактировать (Четкость): Мне нужны дополнительные значащие цифры, а не дополнительный диапазон.

Ответы [ 8 ]

78 голосов
/ 21 июля 2011

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

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

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

11 голосов
/ 21 июля 2011

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

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

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

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

Может быть, кто-то еще может придумать что-нибудь умное, но мой ответ «это невозможно».(Или, по крайней мере, «не проще, чем использование 64-битной структуры и реализация ваших собственных операций»)

6 голосов
/ 21 июля 2011

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

5 голосов
/ 21 июля 2011

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

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

3 голосов
/ 21 июля 2011

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

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


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

3 голосов
/ 21 июля 2011

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

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

1 голос
/ 21 июля 2011

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

0 голосов
/ 02 августа 2013

Это похоже на арифметику двойных-двойных , используемую многими компиляторами для long double на некоторых машинах, которые имеют только аппаратную поддержку вычисления double. Он также используется как float-float на старых графических процессорах NVIDIA, где нет поддержки double. См. Эмуляция FP64 с 2 FP32 на GPU . Таким образом, вычисления будут намного быстрее, чем программная библиотека с плавающей точкой.

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

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

...