What is the right way to convert from Double to Fixed in Haskell?

Viewed 201

I have some code that uses Centi for its currency type. It receives Doubles from an Excel spreadsheet using the xlsx package. I want to convert these Doubles into Centis correctly. I have tried using realToFrac, and for the most part it works, but occasionally it's out by a cent:

λ realToFrac (-1372.92 :: Double) :: Centi
-1372.93

I can guess that the problem is in the binary representation of that decimal number not being exact, and that I shouldn't be using Double to represent currency in the first place, but I don't have control of that part. So what is a fail-safe way of doing the conversion?

1 Answers

Maybe not the best way but one is to round to the closest integer after adjusting for the desired precision:

floatToCenti :: Double -> Centi
floatToCenti = floatToFixed

floatToFixed :: HasResolution a => Double -> Fixed a
floatToFixed x = y where
  y = MkFixed (round (fromInteger (resolution y) * x))
  -- reusing y as the dummy argument of resolution
Related