
On Mon, Sep 20, 2010 at 22:11, Conrad Parker
I've been using unsafeCoerce:
getFloat64be :: Get Double getFloat64be = do n <- getWord64be return (unsafeCoerce n :: Double)
putFloat64be :: Double -> Put putFloat64be n = putWord64be (unsafeCoerce n :: Word64)
but only tested it with quickcheck -- it passes about 10^7 checks, comparing roundtrips in combinatrion with the previous data-binary-ieee754 versions. However could that sometimes behave incorrectly?
QuickCheck only generates a subset of possible floating point values; when I tested unsafeCoerce, it sometimes gave incorrect results when dealing with edge cases like signaling NaNs.
Should the d-b-iee754-0.4.2 versions with castPtr etc. be even faster?
It should be slightly slower, but not nearly as slow as the
bitfield-based parsing.
On Tue, Sep 21, 2010 at 07:10, Daniel Fischer
And I'd expect it to be a heck of a lot faster than the previous implementation. Have you done any benchmarks?
Only very rough ones -- a few basic Criterion checks, but nothing extensive. Numbers for put/get of 64-bit big-endian: getWord getFloat putWord putFloat Bitfields (0.4.1) 59 ns 8385 ns 1840 ns 11448 ns poke/peek (0.4.2) 59 ns 305 ns 1840 ns 744 ns unsafeCoerce 59 ns 61 ns 1840 ns 642 ns Note: I don't know why the cast-based versions can put a Double faster than a Word64; Float is (as expected) slower than Word32. Some special-case GHC optimization?
One problem I see with both, unsafeCoerce and poke/peek is endianness. Will the bit-pattern of a double be interpreted as the same uint64_t on little-endian and on big-endian machines? In other words, is the byte order for doubles endianness-dependent too? If yes, that's fine, if no, it would break between machines of different endianness.
Endianness only matters when marshaling bytes into a single value -- Data.Binary.Get/Put handles that. Once the data is encoded as a Word, endianness is no longer relevant.