FloatingHex 0.1 → 0.2
raw patch · 4 files changed
+56/−37 lines, 4 filesdep ~template-haskellPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: template-haskell
API changes (from Hackage documentation)
+ Data.Numbers.FloatingHex: readHFloat :: RealFloat a => String -> Maybe a
Files
- CHANGES.md +6/−6
- Data/Numbers/FloatingHex.hs +42/−23
- FloatingHex.cabal +2/−2
- README.md +6/−6
CHANGES.md view
@@ -1,13 +1,13 @@ * Hackage: <http://hackage.haskell.org/package/FloatingHex> * GitHub: <http://github.com/LeventErkok/FloatingHex/> -* Latest Hackage released version: 0.1, 2017-01-14+* Latest Hackage released version: 0.2, 2017-01-14 +### Version 0.2, 2017-01-14++ * Support for parsing nan/infinity values+ * Make the printer compliant with printf %a modifier in C+ ### Version 0.1, 2017-01-14 * First implementation. The quasiquoter and the pretty-printer are implemented.-- * NB. The pretty-printer is currently not 100% compatible with the %a modifier- of C printf function. While it will print correct values, it will not always- print the same string as C does. (Note that string representations are not- unique for hexadecimal floats, similar to the scientific notation.)
Data/Numbers/FloatingHex.hs view
@@ -12,16 +12,29 @@ -- We slightly diverge from the standard and do not allow for the "floating-suffix," -- as the type inference of Haskell makes this unnecessary. ------------------------------------------------------------------------------module Data.Numbers.FloatingHex (hf, showHFloat) where+module Data.Numbers.FloatingHex (hf, readHFloat, showHFloat) where import Data.Char (toLower) import Data.Ratio ((%))-import Numeric (showHex)+import Numeric (showHex, floatToDigits) import qualified Language.Haskell.TH.Syntax as TH import Language.Haskell.TH.Quote --- | Turn a hexadecimal float to an internal double, if parseable.+-- | Read a float in hexadecimal binary format. Supports negative numbers, and nan/infinity as well.+-- For regular usage, the quasiquoter (`hf`) should be employed. But this function can be handy for+-- programmatic interfaces.+readHFloat :: RealFloat a => String -> Maybe a+readHFloat = cvt+ where cvt ('-' : cs) = ((-1) *) `fmap` go cs+ cvt cs = go cs++ go "NaN" = Just $ 0/0+ go "Infinity" = Just $ 1/0+ go cs = (fromRational . toRational) `fmap` parseHexFloat cs++-- | Turn a hexadecimal float to an internal double, if parseable. Does not support the leading+-- sign bit. parseHexFloat :: String -> Maybe Double parseHexFloat = go0 . map toLower where go0 ('0':'x':rest) = go1 rest@@ -84,28 +97,34 @@ Just d -> return (TH.LitP (TH.RationalL (toRational d))) Nothing -> fail $ "Invalid hexadecimal floating point number: |" ++ s ++ "|" --- | Show a floating-point value in the hexadecimal format.------ NB. While this function will print a faithful (i.e., correct) value, it is--- not 100% compatible with the @%a@ modifier as found in the C's printf implementation.+-- | Show a floating-point value in the hexadecimal format, similar to the @%a@ modifier in C's printf. -- -- >>> showHFloat (212.21 :: Double) "" -- "0x1.a86b851eb851fp7" -- >>> showHFloat (-12.76 :: Float) ""--- "-0xc.c28f6p0"+-- "-0x1.9851ecp3"+-- >>> showHFloat (-0 :: Double) ""+-- "-0x0p+0" showHFloat :: RealFloat a => a -> ShowS-showHFloat x- | isNaN x = showString "nan"- | isInfinite x = showString $ if x > 0 then "+inf" else "-inf"- | isNegativeZero x = showString "-0x0p1"- | x < 0 = showString $ "-0x" ++ body- | True = showString $ "0x" ++ body- where (m, n) = decodeFloat (abs x)- pre = showHex m ""- (pre', l) = case pre of- "" -> error $ "impossible happened! " ++ show (pre, m)- (f:p) -> (f : trim p, length p)- trim s = case dropWhile (== '0') (reverse s) of- "" -> ""- t -> "." ++ reverse t- body = pre' ++ "p" ++ show (n + 4 * l)+showHFloat = showString . fmt+ where fmt x | isNaN x = "NaN"+ | isInfinite x = (if x < 0 then "-" else "") ++ "Infinity"+ | x < 0 || isNegativeZero x = '-' : cvt (-x)+ | True = cvt x++ cvt x+ | x == 0 = "0x0p+0"+ | True = case floatToDigits 2 x of+ r@([], _) -> error $ "Impossible happened: showHFloat: " ++ show r+ (d:ds, e) -> "0x" ++ show d ++ frac ds ++ "p" ++ show (e-1)++ -- Given binary digits, convert them to hex in blocks of 4+ -- Special case: If all 0's, just drop it.+ frac digits+ | all (== 0) digits = ""+ | True = "." ++ hex digits+ where hex ds+ | null ds = ""+ | length ds < 4 = hex (take 4 (ds ++ repeat 0))+ | True = let (d, r) = splitAt 4 ds in hexDigit d ++ hex r+ hexDigit d = showHex (foldl (\a b -> 2*a+b) 0 d) ""
FloatingHex.cabal view
@@ -1,5 +1,5 @@ Name: FloatingHex-Version: 0.1+Version: 0.2 Synopsis: Read and write hexadecimal floating point numbers Description: Read and write hexadecimal floating point numbers. Provides a quasiquoter for entering hex-float literals, and a function for printing them in hexadecimal.@@ -16,7 +16,7 @@ Copyright: Levent Erkok Category: Tools Build-type: Simple-Cabal-version: >= 1.10+Cabal-version: >= 1.14 Extra-Source-Files: INSTALL, README.md, COPYRIGHT, CHANGES.md source-repository head
README.md view
@@ -10,14 +10,14 @@ as the type inference of Haskell makes this unnecessary. Some examples are: ```- 0x1p+1- 0x1p+8- 0x1.b7p-1- 0x1.fffffffffffffp+1023- 0X1.921FB4D12D84AP-1+ [hf|0x1p+1|]+ [hf|0x1p+8|]+ [hf|0x1.b7p-1|]+ [hf|0x1.fffffffffffffp+1023|]+ [hf|0X1.921FB4D12D84AP-1|] ``` -This format allows for concise and precise string representation for floating point numbers.+This format allows for concise and precise string representation for floating point numbers. Note that you need the `QuasiQuotes` extension of GHC to be able to write these literals. ## Example