Преобразование с плавающей запятой IEEE 754 в Haskell Word32 / 64 в Haskell Float / Double и обратно

Вопрос

В Haskell базовые библиотеки и пакеты Hackage предоставляют несколько средств преобразования двоичных данных с плавающей запятой IEEE-754 в и из поднятого Float и Двойные типы. Однако точность, производительность и переносимость этих методов неясны.

Для целевой библиотеки GHC, предназначенной для (де) сериализации двоичного формата между платформами, каков наилучший подход для обработки данных с плавающей запятой IEEE-754?

Подходы

Это методы, с которыми я сталкивался в существующих библиотеках и онлайн-ресурсах.

Маршалинг FFI

Это подход, используемый пакетом data-binary-ieee754 . Поскольку Float , Double , Word32 и Word64 являются экземплярами Storable , каждый может ткнуть значение исходного типа во внешний буфер, а затем просмотр значения целевого типа:

toFloat :: (F.Storable word, F.Storable float) => word -> float
toFloat word = F.unsafePerformIO $ F.alloca $ \buf -> do
    F.poke (F.castPtr buf) word
    F.peek buf

На моей машине это работает, но я съеживаюсь, когда вижу, что выделение выполняется только для выполнения принуждение. Кроме того, хотя это и не уникально для этого решения, здесь подразумевается, что IEEE-754 на самом деле является представлением в памяти. Тесты, сопровождающие пакет, дают ему знак одобрения «работает на моей машине», но это не идеально.

unsafeCoerce

С таким же неявным предположением о представлении IEEE-754 в памяти следующий код получает печать "работает на моей машине":

toFloat :: Word32 -> Float
toFloat = unsafeCoerce

Преимущество этого метода состоит в том, что оно не выполняет явное выделение, как описано выше, но в документации говорится: «Вы несете ответственность за то, чтобы старые и новые типы имеют идентичные внутренние представления ». Это неявное предположение по-прежнему выполняет всю работу и становится еще более трудоемким при работе с поднятыми типами.

unsafeCoerce #

Расширение границ того, что можно было бы считать «переносимым»:

toFloat :: Word -> Float
toFloat (W# w) = F# (unsafeCoerce# w)

Кажется, это работает, но вообще не кажется практичным, поскольку он ограничен типами GHC.Exts . Приятно обойти поднятые типы, но это все, что можно сказать.

encodeFloat и decodeFloat

Этот подход обладает прекрасным свойством обхода всего с помощью unsafe в название, но, похоже, не совсем соответствует IEEE-754. Предыдущий ответ SO на аналогичный вопрос предлагает сжатый подход, а пакет ieee754-parser использовал более общий подход, прежде чем был объявлен устаревшим в пользу data-binary-ieee754. .

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

38
задан Community 23 May 2017 в 12:18
поделиться