diff --git a/src/Servant/Common/Text.hs b/src/Servant/Common/Text.hs index cc8cb15d..0d2697d4 100644 --- a/src/Servant/Common/Text.hs +++ b/src/Servant/Common/Text.hs @@ -11,6 +11,7 @@ import Data.String.Conversions (cs) import Data.Text (Text) import Data.Text.Read (Reader, decimal, rational, signed) import Data.Word (Word, Word16, Word32, Word64, Word8) +import GHC.Float (double2Float) -- | For getting values from url captures and query string parameters -- Instances should obey: @@ -130,7 +131,9 @@ instance ToText Double where toText = cs . show instance FromText Float where - fromText = runReader rational + -- Double is more practically accurate due to weird rounding when using + -- rational. We convert to double and then convert to Float. + fromText = fmap double2Float . runReader rational instance ToText Float where toText = cs . show diff --git a/test/Servant/Common/TextSpec.hs b/test/Servant/Common/TextSpec.hs index d5c98b1f..0f0ece51 100644 --- a/test/Servant/Common/TextSpec.hs +++ b/test/Servant/Common/TextSpec.hs @@ -55,11 +55,19 @@ spec = describe "Servant.Common.Text" $ do it "holds for Integer" $ property $ \x -> textLaw (x :: Integer) + -- The following two properties are only reasonably expected to hold up + -- to a certain precision. + -- + -- http://en.wikipedia.org/wiki/Floating_point#Internal_representation it "holds for Double" $ - property $ \x -> textLaw (x :: Double) + property $ \x -> + x < 1.0e15 && x > 1.0e-16 ==> + textLaw (x :: Double) it "holds for Float" $ - property $ \x -> textLaw (x :: Float) + property $ \x -> + x < 1.0e7 && x > 1.0e-7 ==> + textLaw (x :: Float) textLaw :: (FromText a, ToText a, Eq a) => a -> Bool textLaw a = fromText (toText a) == Just a