В Haskell базовые
библиотеки и пакеты Hackage предоставляют несколько средств преобразования двоичных данных с плавающей запятой IEEE-754 в и из поднятого Float
и Двойные
типы. Однако точность, производительность и переносимость этих методов неясны.
Для целевой библиотеки GHC, предназначенной для (де) сериализации двоичного формата между платформами, каков наилучший подход для обработки данных с плавающей запятой IEEE-754?
Это методы, с которыми я сталкивался в существующих библиотеках и онлайн-ресурсах.
Это подход, используемый пакетом 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
, которые, по-видимому, чревата несоответствиями . Я пока не нашел способа обойти эти проблемы.