crackNum-3.4/0000755000000000000000000000000007346545000011314 5ustar0000000000000000crackNum-3.4/CHANGES.md0000644000000000000000000000542707346545000012716 0ustar0000000000000000* Hackage: * GitHub: * Latest Hackage released version: 3.4, 2023-04-14 ### Version 3.4, 2023-04-14 * Fix compilation in previous build ### Version 3.3, 2023-04-14 * Allow compilation with newer versions of SBV ### Version 3.2, 2021-06-30 * Add an explicit note when conversion is exact. ### Version 3.1, 2021-03-29 * Fix readme ### Version 3.0, 2021-03-29 * A complete rewrite, much simplified, and supporting arbitrary precision floats. Some of the old features and the library are dropped; so if you rely on the library nature of CrackNum, do not upgrade. For other users who merely use crackNum as an executable, the new version is strongly recommended. ### Version 2.4, 2020-09-05 * Changes required to compile cleanly with GHC 8.10.2 ### Version 2.3, 2018-11-17 * Remove dependency on the ieee754 and reinterpret-cast packages. The goal is to remove any FFI dependencies. We now define and export the required utilities directly in the CrackNum package. ### Version 2.2, 2018-09-01 * Instead of data-binary-ieee754, use reinterpret-cast package. According to documents, the former is deprecated. ### Version 2.1, 2018-07-20 * Support for vi-editor bindings. See the file "crackNum.vim" in the distribution or in the github repo You can put "so ~/.vim/crackNum.vim" (use the correct path!) and have vi crack numbers directly from inside your editor. Simply locate your cursor on a binary/hex stream of digits and type ":CrackNum". See the "crackNum.vim" file for binding details. ### Version 2.0, 2018-03-17 * Import FloatingHex qualified to avoid GHC 8.4.1 compilation issue ### Version 1.9, 2017-01-22 * Minor fix to printing of +/-0 ### Version 1.8, 2017-01-15 * Bump up FloatingHex dependency to >0.4, this enables proper support for large doubles ### Version 1.7, 2017-01-14 * Fix a snafu in reading hexadecimal floats ### Version 1.6, 2017-01-14 * Add support for hexadecimal-floats. These now work both in toIEEE option as input, and also when printing the values out. (i.e., numbers of the form 0x1.abp-3, etc.) ### Version 1.5, 2016-01-23 * Typo fixes; no functionality changes ### Version 1.4, 2016-01-17 * Fix NaN nomenclature: Screaming->Signaling * Add an example to README.md ### Version 1.3, 2015-04-11 * Fix docs, github location ### Version 1.2, 2015-04-11 * Fix the constant qnan values for SP/DP * Add conversions from float/double. Much easier to use. * Better handling of nan values. ### Version 1.1, 2015-04-02 * Clean-up the API, examples etc. ### Version 1.0, 2015-04-01 * First implementation. Supports HP/SP/DP and signed/unsigned numbers in 8/16/32/64 bits. crackNum-3.4/COPYRIGHT0000644000000000000000000000025707346545000012613 0ustar0000000000000000Copyright (c) 2015-2021, Levent Erkok (erkokl@gmail.com) All rights reserved. The crackNum executable is distributed with the BSD3 license. See the LICENSE file for details. crackNum-3.4/LICENSE0000644000000000000000000000305307346545000012322 0ustar0000000000000000crackNum: Cracking various Floating/Integer values Copyright (c) 2015-2021, 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. crackNum-3.4/README.md0000644000000000000000000001057407346545000012602 0ustar0000000000000000## Decode/Encode Integers, Words, and IEE754 Floats On Hackage: http://hackage.haskell.org/package/crackNum ### Example: Encode a decimal number as a single-precision IEEE754 number ``` $ crackNum -fsp -- -2.3e6 Satisfiable. Model: ENCODED = -2300000.0 :: Float 3 2 1 0 1 09876543 21098765432109876543210 S ---E8--- ----------S23---------- Binary layout: 1 10010100 00011000110000110000000 Hex layout: CA0C 6180 Precision: Single Sign: Negative Exponent: 21 (Stored: 148, Bias: 127) Classification: FP_NORMAL Binary: -0b1.0001100011000011p+21 Octal: -0o1.061414p+21 Decimal: -2300000.0 Hex: -0x2.3186p+20 Rounding mode: RNE: Round nearest ties to even. Note: Conversion from "-2.3e6" was exact. No rounding happened. ``` ### Example: Decode a single-precision IEEE754 number float from memory-layout ``` $ crackNum -fsp 0xfc00 abc1 Satisfiable. Model: DECODED = -2.6723903e36 :: Float 3 2 1 0 1 09876543 21098765432109876543210 S ---E8--- ----------S23---------- Binary layout: 1 11111000 00000001010101111000001 Hex layout: FC00 ABC1 Precision: Single Sign: Negative Exponent: 121 (Stored: 248, Bias: 127) Classification: FP_NORMAL Binary: -0b1.00000001010101111000001p+121 Octal: -0o2.00527404p+120 Decimal: -2.6723903e36 Hex: -0x2.02AF04p+120 $ crackNum -fdp 0xfc00 abc1 7F80 0001 ``` ### Example: Decode a custom (2+3) IEEE754 float from memory-layout ``` $ crackNum -f2+3 0b10011 Satisfiable. Model: DECODED = -0.75 :: FloatingPoint 2 3 4 32 10 S E2 S2 Binary layout: 1 00 11 Hex layout: 13 Precision: 2 exponent bits, 2 significand bits Sign: Negative Exponent: 0 (Subnormal, with fixed exponent value. Stored: 0, Bias: 1) Classification: FP_SUBNORMAL Binary: -0b1.1p-1 Octal: -0o6p-3 Decimal: -0.75 Hex: -0xcp-4 ``` ### Example: Encode an integer as a 7-bit signed word ``` $ crackNum -i7 12 Satisfiable. Model: ENCODED = 12 :: IntN 7 654 3210 Binary layout: 000 1100 Hex layout: 0C Type: Signed 7-bit 2's complement integer Sign: Positive Binary: 0b1100 Octal: 0o14 Decimal: 12 Hex: 0xc ``` ### Usage info ``` Usage: crackNum value OR binary/hex-pattern -i N Signed integer of N-bits -w N Unsigned integer of N-bits -f fp Floating point format fp -r rm Rounding mode to use. If not given, Nearest-ties-to-Even. -h, -? --help print help, with examples -v --version print version info Examples: Encoding: crackNum -i4 -- -2 -- encode as 4-bit signed integer crackNum -w4 2 -- encode as 4-bit unsigned integer crackNum -f3+4 2.5 -- encode as float with 3 bits exponent, 4 bits significand crackNum -f3+4 2.5 -rRTZ -- encode as above, but use RTZ rounding mode. crackNum -fbp 2.5 -- encode as a brain-precision float crackNum -fdp 2.5 -- encode as a double-precision float Decoding: crackNum -i4 0b0110 -- decode as 4-bit signed integer, from binary crackNum -w4 0xE -- decode as 4-bit unsigned integer, from hex crackNum -f3+4 0b0111001 -- decode as float with 3 bits exponent, 4 bits significand crackNum -fbp 0x000F -- decode as a brain-precision float crackNum -fdp 0x8000000000000000 -- decode as a double-precision float Notes: - For encoding: - Use -- to separate your argument if it's a negative number. - For floats: You can pass in NaN, Inf, -0, -Inf etc as the argument, along with a decimal float. - For decoding: - Use hexadecimal (0x) or binary (0b) as input. Input must have one of these prefixes. - You can use _,- or space as a digit to improve readability for the pattern to be decoded ``` VIM users: You can use the http://github.com/LeventErkok/crackNum/blob/master/crackNum.vim file to use CrackNum directly from VIM. Simply locate your cursor on the text to crack, and use the command `:CrackNum options`. crackNum-3.4/Setup.hs0000644000000000000000000000070507346545000012752 0ustar0000000000000000----------------------------------------------------------------------------- -- | -- Module : Main -- Copyright : (c) Levent Erkok -- License : BSD3 -- Maintainer : erkokl@gmail.com -- Stability : experimental -- -- Setup module for crackNum ----------------------------------------------------------------------------- {-# OPTIONS_GHC -Wall #-} module Main(main) where import Distribution.Simple main :: IO () main = defaultMain crackNum-3.4/crackNum.cabal0000644000000000000000000000232207346545000014042 0ustar0000000000000000Cabal-version : 2.2 Name : crackNum Version : 3.4 Synopsis : Crack various integer and floating-point data formats Description : Crack IEEE-754 float formats and arbitrary sized words and integers, showing the layout. . For details, please see: License : BSD-3-Clause License-file : LICENSE Author : Levent Erkok Homepage : http://github.com/LeventErkok/CrackNum Maintainer : erkokl@gmail.com Copyright : Levent Erkok Category : Tools Build-type : Simple Extra-Source-Files : README.md, COPYRIGHT, CHANGES.md Tested-With : GHC==9.6.1 source-repository head type: git location: git://github.com/LeventErkok/crackNum.git Executable crackNum main-is : CrackNum/Main.hs default-language: Haskell2010 hs-source-dirs : src ghc-options : -Wall -Wunused-packages build-depends : base >= 4.11 && < 5, libBF, sbv >= 10.0 , tasty, tasty-golden, filepath, directory, process other-modules : Paths_crackNum, CrackNum.TestSuite autogen-modules : Paths_crackNum crackNum-3.4/src/CrackNum/0000755000000000000000000000000007346545000013606 5ustar0000000000000000crackNum-3.4/src/CrackNum/Main.hs0000644000000000000000000004352307346545000015035 0ustar0000000000000000--------------------------------------------------------------------------- -- | -- Module : Main -- Copyright : (c) Levent Erkok -- License : BSD3 -- Maintainer : erkokl@gmail.com -- Stability : experimental -- -- Main entry point for the crackNum executable ----------------------------------------------------------------------------- {-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -Wall -Werror #-} module Main(main) where import System.Environment (getArgs, getProgName, withArgs) import Data.Char (isDigit, isSpace, toLower) import Data.List (isPrefixOf, isSuffixOf, unfoldr) import System.Console.GetOpt (ArgOrder(Permute), getOpt, ArgDescr(..), OptDescr(..), usageInfo) import System.Exit (exitFailure) import Text.Read (readMaybe) import System.IO (hPutStr, stderr) import LibBF import Numeric import Data.SBV hiding (crack) import Data.SBV.Float hiding (FP) import Data.SBV.Dynamic hiding (satWith) import Data.SBV.Internals hiding (free) import Data.Version (showVersion) import Paths_crackNum (version) import CrackNum.TestSuite -- | Copyright info copyRight :: String copyRight = "(c) Levent Erkok. Released with a BSD3 license." -- | Various precisions we support data FP = SP -- Single precision | DP -- Double precision | FP Int Int -- Arbitrary precision with given exponent and significand sizes deriving (Show, Eq) -- | How many bits does this float occupy fpSize :: FP -> Int fpSize SP = 32 fpSize DP = 64 fpSize (FP i j) = i+j -- | Rounding modes we support data RM = RNE -- ^ Round nearest ties to even | RNA -- ^ Round nearest ties to away | RTP -- ^ Round towards positive infinity | RTN -- ^ Round towards negative infinity | RTZ -- ^ Round towards zero deriving (Eq, Enum, Bounded) -- | Show instance for RM, for descriptive purposes instance Show RM where show RNE = "RNE: Round nearest ties to even." show RNA = "RNA: Round nearest ties to away." show RTP = "RTP: Round towards positive infinity." show RTN = "RTN: Round towards negative infinity." show RTZ = "RTZ: Round towards zero." -- Covert to LibBF rounding mode toLibBFRM :: RM -> RoundMode toLibBFRM RNE = NearEven toLibBFRM RNA = NearAway toLibBFRM RTP = ToPosInf toLibBFRM RTN = ToNegInf toLibBFRM RTZ = ToZero -- | Options accepted by the executable data Flag = Signed Int -- ^ Crack as a signed word with the given number of bits | Unsigned Int -- ^ Crack as an unsigned word with the given number of bits | Floating FP -- ^ Crack as the corresponding floating-point type | RMode RM -- ^ Rounding mode to use | BadFlag [String] -- ^ Bad input | Version -- ^ Version | Help -- ^ Show help deriving (Show, Eq) -- | Is this a rounding flag? isRMode :: Flag -> Bool isRMode RMode{} = True isRMode _ = False -- | Given an integer flag value, turn it into a flag getSize :: String -> (Int -> Flag) -> String -> Flag getSize flg f n = case readMaybe n of Just i | i > 0 -> f i | True -> BadFlag ["Option " ++ show flg ++ " requires an integer >= 1. Received: " ++ show n] Nothing -> BadFlag ["Option " ++ show flg ++ " requires an integer argument. Received: " ++ show n] #include "MachDeps.h" #define FP_MIN_EB 2 #define FP_MIN_SB 2 #if WORD_SIZE_IN_BITS == 64 #define FP_MAX_EB 61 #define FP_MAX_SB 4611686018427387902 #else #define FP_MAX_EB 29 #define FP_MAX_SB 1073741822 #endif -- | Given a float flag value, turn it into a flag getFP :: String -> Flag getFP "hp" = Floating $ FP 5 11 getFP "bp" = Floating $ FP 8 8 getFP "sp" = Floating SP getFP "dp" = Floating DP getFP "qp" = Floating $ FP 15 113 getFP ab = case span isDigit ab of (eb@(_:_), '+':r) -> case span isDigit r of (sp@(_:_), "") -> mkEBSB (read eb) (read sp) _ -> bad _ -> bad where bad = BadFlag [ "Option " ++ show "-f" ++ " requires one of:" , "" , " hp: Half float ( 5 + 11)" , " bp: Brain float ( 8 + 8)" , " sp: Single precision ( 8 + 24)" , " dp: Single precision (11 + 53)" , " qp: Quad precision (15 + 113)" , " a+b: Arbitrary precision ( a + b)" , "" , "where first number is the number of bits in the exponent" , "and the second number is the number of bits in the significand, including the implicit bit." ] mkEBSB :: Int -> Int -> Flag mkEBSB eb sb | eb >= FP_MIN_EB && eb <= FP_MAX_EB && sb >= FP_MIN_SB && sb <= FP_MAX_SB = Floating $ FP eb sb | True = BadFlag [ "Invalid floating-point precision." , "" , " Exponent size must be between " ++ show (FP_MIN_EB :: Int) ++ " to " ++ show (FP_MAX_EB :: Int) , " Significant size must be between " ++ show (FP_MIN_SB :: Int) ++ " to " ++ show (FP_MAX_SB :: Int) , "" , "Received: " ++ show eb ++ " " ++ show sb ] getRM :: String -> Flag getRM "rne" = RMode RNE getRM "rna" = RMode RNA getRM "rtp" = RMode RTP getRM "rtn" = RMode RTN getRM "rtz" = RMode RTZ getRM m = BadFlag $ [ "Invalid rounding mode." , "" , " Must be one of:" ] ++ [ " " ++ show r | r <- [minBound .. maxBound::RM]] ++ [ "" , "Received: " ++ m ] -- | Options we accept pgmOptions :: [OptDescr Flag] pgmOptions = [ Option "i" [] (ReqArg (getSize "-i" Signed) "N" ) "Signed integer of N-bits" , Option "w" [] (ReqArg (getSize "-w" Unsigned) "N" ) "Unsigned integer of N-bits" , Option "f" [] (ReqArg getFP "fp") "Floating point format fp" , Option "r" [] (ReqArg (getRM . map toLower) "rm") "Rounding mode to use. If not given, Nearest-ties-to-Even." , Option "h?" ["help"] (NoArg Help) "print help, with examples" , Option "v" ["version"] (NoArg Version) "print version info" ] -- | Help info helpStr :: String -> String helpStr pn = usageInfo ("Usage: " ++ pn ++ " value OR binary/hex-pattern") pgmOptions -- | Print usage info and examples. usage :: String -> IO () usage pn = putStr $ unlines [ helpStr pn , "Examples:" , " Encoding:" , " " ++ pn ++ " -i4 -- -2 -- encode as 4-bit signed integer" , " " ++ pn ++ " -w4 2 -- encode as 4-bit unsigned integer" , " " ++ pn ++ " -f3+4 2.5 -- encode as float with 3 bits exponent, 4 bits significand" , " " ++ pn ++ " -f3+4 2.5 -rRTZ -- encode as above, but use RTZ rounding mode." , " " ++ pn ++ " -fbp 2.5 -- encode as a brain-precision float" , " " ++ pn ++ " -fdp 2.5 -- encode as a double-precision float" , "" , " Decoding:" , " " ++ pn ++ " -i4 0b0110 -- decode as 4-bit signed integer, from binary" , " " ++ pn ++ " -w4 0xE -- decode as 4-bit unsigned integer, from hex" , " " ++ pn ++ " -f3+4 0b0111001 -- decode as float with 3 bits exponent, 4 bits significand" , " " ++ pn ++ " -fbp 0x000F -- decode as a brain-precision float" , " " ++ pn ++ " -fdp 0x8000000000000000 -- decode as a double-precision float" , "" , " Notes:" , " - For encoding:" , " - Use -- to separate your argument if it's a negative number." , " - For floats: You can pass in NaN, Inf, -0, -Inf etc as the argument, along with a decimal float." , " - For decoding:" , " - Use hexadecimal (0x) or binary (0b) as input. Input must have one of these prefixes." , " - You can use _,- or space as a digit to improve readability for the pattern to be decoded" ] -- | Terminate early die :: [String] -> IO a die xs = do hPutStr stderr $ unlines $ "ERROR:" : map (" " ++) xs exitFailure -- | main entry point to crackNum crack :: String -> [String] -> IO () crack pn argv = case getOpt Permute pgmOptions argv of (_, _, errs@(_:_)) -> die $ errs ++ lines (helpStr pn) (os, rs, []) | Version `elem` os -> putStrLn $ pn ++ " v" ++ showVersion version ++ ", " ++ copyRight | Help `elem` os -> usage pn | True -> do let rm = case reverse [r | RMode r <- os] of (r:_) -> r _ -> RNE arg = dropWhile isSpace $ unwords rs case ([b | BadFlag b <- os], filter (not . isRMode) os) of (e:_, _) -> die e (_, [Signed n]) -> process (SInt n) rm arg (_, [Unsigned n]) -> process (SWord n) rm arg (_, [Floating s]) -> process (SFloat s) rm arg _ -> usage pn -- | Kinds of numbers we understand data NKind = SInt Int -- ^ Signed integer of n bits | SWord Int -- ^ Unsigned integer of n bits | SFloat FP -- ^ Floating point with precision -- | main entry point to crackNum main :: IO () main = do argv <- getArgs pn <- getProgName let rt = "--runTests" if rt `elem` argv then withArgs (filter (`notElem` [rt, "--"]) argv) runTests else crack pn argv -- | Perform the encoding/decoding process :: NKind -> RM -> String -> IO () process num rm inp = case num of SInt n -> print =<< (if decode then di else ei) True n SWord n -> print =<< (if decode then di else ei) False n SFloat s -> (if decode then df else ef) s where decode = any (`isPrefixOf` inp) ["0x", "0b"] bitString n = do let isSkippable c = c `elem` "_-" || isSpace c (isHex, stream) <- case map toLower (filter (not . isSkippable) inp) of '0':'x':rest -> pure (True, rest) '0':'b':rest -> pure (False, rest) _ -> die [ "Input string must start with 0b or 0x for decoding." , "Received prefix: " ++ show (take 2 inp) ] let cvtBin '1' = pure [True] cvtBin '0' = pure [False] cvtBin c = die ["Input has a non-binary digit: " ++ show c] cvtHex c = case readHex [c] of [(v, "")] -> pure $ pad $ map (== (1::Int)) $ reverse $ unfoldr (\x -> if x == 0 then Nothing else Just (x `rem` 2, x `div` 2)) v _ -> die ["Input has a non-hexadecimal digit: " ++ show c] where pad p = replicate (4 - length p) False ++ p cvt i | isHex = concat <$> mapM cvtHex i | True = concat <$> mapM cvtBin i encoded <- cvt stream let bits 1 = "one bit" bits b = show b ++ " bits" case length encoded `compare` n of EQ -> pure encoded LT -> die ["Input needs to be " ++ show n ++ " bits wide, it's too short by " ++ bits (n - length encoded)] GT -> die ["Input needs to be " ++ show n ++ " bits wide, it's too long by " ++ bits (length encoded - n)] di :: Bool -> Int -> IO SatResult di sgn n = do bs <- bitString n satWith z3{crackNum=True} $ p bs where p :: [Bool] -> ConstraintSet p bs = do x <- (if sgn then sIntN else sWordN) n "DECODED" mapM_ constrain $ zipWith (.==) (map SBV (svBlastBE x)) (map literal bs) ei :: Bool -> Int -> IO SatResult ei sgn n = case reads inp of [(v :: Integer, "")] -> satWith z3{crackNum=True} $ p v _ -> die ["Expected an integer value to decode, received: " ++ show inp] where p :: Integer -> Predicate p iv = do let k = KBounded sgn n v = SBV $ SVal k $ Left $ mkConstCV k iv x <- (if sgn then sIntN else sWordN) n "ENCODED" pure $ SBV x .== v df :: FP -> IO () df fp = do bs <- map literal <$> bitString (fpSize fp) case fp of SP -> print =<< satWith z3{crackNum=True} (dFloat bs) DP -> print =<< satWith z3{crackNum=True} (dDouble bs) FP i j -> print =<< satWith z3{crackNum=True} (dFP i j bs) dFloat :: [SBool] -> ConstraintSet dFloat bs = do x <- sFloat "DECODED" let (s, e, m) = blastSFloat x mapM_ constrain $ zipWith (.==) (s : e ++ m) bs dDouble :: [SBool] -> ConstraintSet dDouble bs = do x <- sDouble "DECODED" let (s, e, m) = blastSDouble x mapM_ constrain $ zipWith (.==) (s : e ++ m) bs dFP :: Int -> Int -> [SBool] -> ConstraintSet dFP i j bs = do sx <- svNewVar (KFP i j) "DECODED" let bits = svBlastBE sx mapM_ constrain $ zipWith (.==) (map SBV bits) bs convert :: Int -> Int -> (BigFloat, Maybe String) convert i j = case s of Ok -> (v, Nothing) _ -> (v, Just (trim (show s))) where bfOpts = allowSubnormal <> rnd (toLibBFRM rm) <> expBits (fromIntegral i) <> precBits (fromIntegral j) (v, s) = bfFromString 10 bfOpts inp trim xs | "[" `isPrefixOf` xs && "]" `isSuffixOf` xs = init (tail xs) | True = xs note :: Maybe String -> IO () note mbs = do putStrLn $ " Rounding mode: " ++ show rm case mbs of Nothing -> putStrLn $ " Note: Conversion from " ++ show inp ++ " was exact. No rounding happened." Just s -> putStrLn $ " Note: Conversion from " ++ show inp ++ " was not faithful. Status: " ++ s ++ "." ef :: FP -> IO () ef SP = case reads (fixup inp) of [(v :: Float, "")] -> do print =<< satWith z3{crackNum=True} (p v) note $ snd $ convert 8 24 _ -> ef (FP 8 24) where p :: Float -> Predicate p f = do x <- sFloat "ENCODED" pure $ x .=== literal f ef DP = case reads (fixup inp) of [(v :: Double, "")] -> do print =<< satWith z3{crackNum=True} (p v) note $ snd $ convert 11 53 _ -> ef (FP 11 53) where p :: Double -> Predicate p d = do x <- sDouble"ENCODED" pure $ x .=== literal d ef (FP i j) = do let (v, mbS) = convert i j print =<< satWith z3{crackNum=True} (p v) note mbS where p :: BigFloat -> Predicate p bf = do let k = KFP i j sx <- svNewVar k "ENCODED" pure $ SBV $ sx `svStrongEqual` SVal k (Left (CV k (CFP (fpFromBigFloat i j bf)))) -- | Convert certain strings to more understandable format by read fixup :: String -> String fixup inp | linp `elem` ["inf", "infinity"] = "Infinity" | linp `elem` ["-inf", "-infinity"] = "-Infinity" | linp == "nan" = "NaN" | linp == "-nan" = "-NaN" | True = inp where linp = map toLower inp crackNum-3.4/src/CrackNum/TestSuite.hs0000644000000000000000000000455207346545000016101 0ustar0000000000000000--------------------------------------------------------------------------- -- | -- Module : TestSuite -- Copyright : (c) Levent Erkok -- License : BSD3 -- Maintainer : erkokl@gmail.com -- Stability : experimental -- -- Test-suite for crackNum ----------------------------------------------------------------------------- {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -Wall -Werror #-} module CrackNum.TestSuite(runTests) where import Control.Exception as C import Test.Tasty import Test.Tasty.Golden (goldenVsFileDiff) import System.FilePath import System.Directory (removeFile) import System.Process (readProcessWithExitCode) import Data.List (intercalate) gold :: TestName -> [String] -> TestTree gold n args = goldenVsFileDiff n diff gf gfTmp (rm gfTmp >> run) where gf = "Golds" n <.> "gold" gfTmp = gf ++ "_temp" rm f = removeFile f `C.catch` (\(_ :: C.SomeException) -> return ()) as = unwords args run = do (ec, so, se) <- readProcessWithExitCode "crackNum" args "" writeFile gfTmp $ intercalate "\n" $ [ "Arguments: " ++ as , "Exit code: " ++ show ec , so ] ++ concat [["STDERR:", se] | not (null se)] diff ref new = ["diff", "-w", "-u", ref, new] -- | run the test suite runTests :: IO () runTests = defaultMain tests tests :: TestTree tests = testGroup "CrackNum" [ testGroup "Encode" [ gold "encode0" ["-i4", "--", "-2"] , gold "encode1" ["-w4", "2"] , gold "encode2" ["-f3+4", "2.5"] , gold "encode3" ["-f3+4", "2.5", "-rRTZ"] , gold "encode4" ["-fbp", "2.5"] , gold "encode5" ["-fdp", "2.5"] ] , testGroup "Decode" [ gold "decode0" ["-i4", "0b0110"] , gold "decode1" ["-w4", "0xE"] , gold "decode2" ["-f3+4", "0b0111001"] , gold "decode3" ["-fbp", "0x000F"] , gold "decode4" ["-fdp", "0x8000000000000000"] ] , testGroup "Bad" [ gold "badInvocation0" ["-f3+4", "0b01"] , gold "badInvocation1" ["-f3+4", "0xFFFF"] ] ]