FloatingHex-0.5/0000755000000000000000000000000007346545000011757 5ustar0000000000000000FloatingHex-0.5/CHANGES.md0000755000000000000000000000162207346545000013355 0ustar0000000000000000* Hackage: * GitHub: * Latest Hackage released version: 0.5, 2020-09-05 ### Version 0.5, 2020-09-05 * Changes to make it work with GHC 8.10.2 ### Version 0.4, 2017-01-15 * Export the new FloatingHexReader class. Useful when used as an API. ### Version 0.3, 2017-01-15 * Bump up template-haskell dependency to >= 2.10. As noted by Herbert Valerio Riedel, FloatingHex fails to compile with older versions. * Make the double->float conversions more robust, by avoiding the rational route. (Avoids issues in https://ghc.haskell.org/trac/ghc/ticket/3676) ### 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. FloatingHex-0.5/COPYRIGHT0000755000000000000000000000025207346545000013254 0ustar0000000000000000Copyright (c) 2017, Levent Erkok (erkokl@gmail.com) All rights reserved. The FloatingHex library is distributed with the BSD3 license. See the LICENSE file for details. FloatingHex-0.5/Data/Numbers/0000755000000000000000000000000007346545000014243 5ustar0000000000000000FloatingHex-0.5/Data/Numbers/FloatingHex.hs0000644000000000000000000001412207346545000017007 0ustar0000000000000000------------------------------------------------------------------------- -- | -- Module : Data.Numbers.FloatingHex -- Copyright : (c) Levent Erkok -- License : BSD3 -- Maintainer : erkokl@gmail.com -- Stability : experimental -- -- Reading/Writing hexadecimal floating-point numbers. -- -- See: , pages 57-58. -- 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 ( -- ** QuasiQuoting hf -- ** Reading hex-floats , FloatingHexReader(..) -- ** Showing hex-floats , showHFloat ) where import Data.Char (toLower) import Data.Ratio ((%)) import Numeric (showHex) import GHC.Float import qualified Language.Haskell.TH.Syntax as TH import Language.Haskell.TH.Quote -- | Due to intricacies of conversion between -- @Float@ and @Double@ types (see ), we explicitly introduce -- a class to do the reading properly. class RealFloat a => FloatingHexReader a where -- | Convert a hex-float from a string, if possible. readHFloat :: String -> Maybe a -- | The Float instance instance FloatingHexReader Float where readHFloat s = double2Float `fmap` readHFloatAsDouble s -- | The Double instance instance FloatingHexReader Double where readHFloat = readHFloatAsDouble -- | 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. readHFloatAsDouble :: String -> Maybe Double readHFloatAsDouble = cvt where cvt ('-' : cs) = ((-1) *) `fmap` go cs cvt cs = go cs go "NaN" = Just $ 0/0 go "Infinity" = Just $ 1/0 go cs = parseHexFloat cs -- | Turn a hexadecimal float to an internal double, if parseable. Does not support the leading -- '-' bit, although it does allow a leading +. (The former is best done out of the quasiquote, -- since TH does not cannot represent negative 0! See -- for why we avoid this here.) parseHexFloat :: String -> Maybe Double parseHexFloat = goS . map toLower where goS ('+':rest) = go0 rest goS cs = go0 cs go0 ('0':'x':rest) = go1 rest go0 _ = Nothing go1 cs = case break (== 'p') cs of (pre, 'p':'+':d) -> go2 pre d (pre, 'p': d) -> go2 pre d _ -> Nothing go2 cs = case break (== '.') cs of (pre, '.':post) -> construct pre post _ -> construct cs "" rd :: Read a => String -> Maybe a rd s = case reads s of [(x, "")] -> Just x _ -> Nothing construct pre post d = do a <- rd $ "0x" ++ pre ++ post e <- rd d return $ val a (length post) e val :: Integer -> Int -> Integer -> Double val a b e | e > 0 = fromRational $ (top * power) % bot | True = fromRational $ top % (power * bot) where top, bot, power :: Integer top = a bot = 16 ^ b power = 2 ^ abs e -- | A quasiquoter for hexadecimal floating-point literals. -- See: , pages 57-58. -- We slightly diverge from the standard and do not allow for the "floating-suffix," -- as the type inference of Haskell makes this unnecessary. -- -- Example: -- -- > {-# LANGUAGE QuasiQuotes #-} -- > import Data.Numbers.FloatingHex -- > -- > f :: Double -- > f = [hf|0x1.f44abd5aa7ca4p+25|] -- -- With these definitions, @f@ will be equal to the number @6.5574266708245546e7@ hf :: QuasiQuoter hf = QuasiQuoter { quoteExp = q , quotePat = p , quoteType = error "Unexpected hexadecimal float in a type context" , quoteDec = error "Unexpected hexadecimal float in a declaration context" } where q :: String -> TH.Q TH.Exp q s = case parseHexFloat s of Just d -> TH.lift d Nothing -> fail $ "Invalid hexadecimal floating point number: |" ++ s ++ "|" p :: String -> TH.Q TH.Pat p s = case parseHexFloat s of 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, similar to the @%a@ specifier in C's printf. -- -- >>> showHFloat (212.21 :: Double) "" -- "0x1.a86b851eb851fp7" -- >>> showHFloat (-12.76 :: Float) "" -- "-0x1.9851ecp3" -- >>> showHFloat (-0 :: Double) "" -- "-0x0p+0" showHFloat :: RealFloat a => a -> ShowS 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-0.5/FloatingHex.cabal0000644000000000000000000000246507346545000015162 0ustar0000000000000000Name: FloatingHex Version: 0.5 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. . See: , pages 57-58. We slightly diverge from the standard and do not allow for the "floating-suffix," as the type inference of Haskell makes this unnecessary. . For details, please see: License: BSD3 License-file: LICENSE Author: Levent Erkok Maintainer: erkokl@gmail.com Copyright: Levent Erkok Category: Tools Build-type: Simple Cabal-version: >= 1.14 Extra-Source-Files: INSTALL, README.md, COPYRIGHT, CHANGES.md source-repository head type: git location: git://github.com/LeventErkok/FloatingHex.git Library ghc-options : -Wall default-language: Haskell2010 Build-Depends : base >= 4 && < 5, template-haskell >= 2.10 Exposed-modules : Data.Numbers.FloatingHex FloatingHex-0.5/INSTALL0000755000000000000000000000016407346545000013014 0ustar0000000000000000The FloatingHex library can be installed simply by issuing cabal install like this: cabal install FloatingHex FloatingHex-0.5/LICENSE0000644000000000000000000000305507346545000012767 0ustar0000000000000000FloatingHex: Read/Write Hexadecimal Floating point values Copyright (c) 2017, Levent Erkok (erkokl@gmail.com) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the developer (Levent Erkok) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEVENT ERKOK BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. FloatingHex-0.5/README.md0000755000000000000000000000305007346545000013237 0ustar0000000000000000## FloatingHex: Read/Write Hexadecimal floats [![Hackage version](http://img.shields.io/hackage/v/FloatingHex.svg?label=Hackage)](http://hackage.haskell.org/package/FloatingHex) [![Build Status](http://img.shields.io/travis/LeventErkok/FloatingHex.svg?label=Build)](http://travis-ci.org/LeventErkok/FloatingHex) ### Hexadecimal Floats For syntax reference, see: , pages 57-58. We slightly diverge from the standard and do not allow for the "floating-suffix," as the type inference of Haskell makes this unnecessary. Some examples are: ``` [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. Note that you need the `QuasiQuotes` extension of GHC to be able to write these literals. ## Example ```haskell {-# LANGUAGE QuasiQuotes #-} import Data.Numbers.FloatingHex -- expressions f :: Double f = [hf|0x1.f44abd5aa7ca4p+25|] -- patterns g :: Float -> String g [hf|0x1p1|] = "two!" g [hf|0x1p-1|] = "half!" g d = "something else: " ++ show d -- showing hexadecimal floats test = showHFloat [hf|0x1.f44abd5aa7ca4p+25|] "" ``` (Note that while the quasiquoter allows for floating-point patterns, it is usually not a good idea to use floating-point literals in pattern matching.) ### Thanks The following people reported bugs, provided comments/feedback, or contributed to the development of FloatingHex in various ways: Herbert Valerio Riedel. FloatingHex-0.5/Setup.hs0000644000000000000000000000071007346545000013411 0ustar0000000000000000----------------------------------------------------------------------------- -- | -- Module : Main -- Copyright : (c) Levent Erkok -- License : BSD3 -- Maintainer : erkokl@gmail.com -- Stability : experimental -- -- Setup module for FloatingHex ----------------------------------------------------------------------------- {-# OPTIONS_GHC -Wall #-} module Main(main) where import Distribution.Simple main :: IO () main = defaultMain