Browse Source

Add dec and bin printing, add help, cleanup range and prompt

Josh Bicking 6 years ago
parent
commit
afc26f00f3
2 changed files with 68 additions and 29 deletions
  1. 4 4
      README.md
  2. 64 25
      app/Main.hs

+ 4 - 4
README.md

@@ -14,7 +14,7 @@ Run `stack exec pi-digits-exe`, or execute the binary found in `./.stack-work/in
 
 ## TODO
 
-- Add a function for converting results to decimal.
-- Implement a faster mod operation, to allow for larger numbers (like 12345678901234567890). It will likely be implemented with the algorithm explained in the paper.
-- Replace the mess in `prompt` with a monad.
-- Implement threading?
+- [X] Add a function for converting results to decimal (and binary).
+- [ ] Implement a faster mod operation, to allow for larger numbers (like 12345678901234567890). It will likely be implemented with the algorithm explained in the paper.
+- [ ] Replace the mess in `prompt` with a monad.
+- [ ] Implement threading?

+ 64 - 25
app/Main.hs

@@ -1,39 +1,47 @@
 module Main where
-import Numeric (showHex)
+import Numeric (showIntAtBase)
 import Data.List (isInfixOf, genericIndex)
 import Data.List.Split(splitOn)
 import Text.Read (readMaybe)
 import System.IO (hFlush, stdout)
+import System.Environment (getArgs)
+import System.Exit (exitWith, ExitCode(ExitSuccess))
 
-hexPi :: Integer -> Char
+
+-- Get the hex representation of Pi at place n.
+hexPi :: Integer -> Integer
 hexPi n =
   let
     summation = (4 * sumPi n 1) - (2 * sumPi n 4) - (sumPi n 5) - (sumPi n 6)
-    skimmedSum = summation - (fromIntegral (floor summation :: Integer))
+    skimmedSum = summation - (fromIntegral (floor summation :: Integer)) -- Take only the decimal portion
   in
-    showHex (floor (16 * skimmedSum) :: Integer) "" !! 0
+    floor (16 * skimmedSum) :: Integer
+
 
+-- Calculate the summation.
+-- 5000 is used in place of Infinity. This value drops off quickly, so no need to go too far.
 sumPi :: Integer -> Integer -> Double
 sumPi n x =
   let
     summation1 = [(fromIntegral ((16^(n-k) `mod` ((8*k)+x)))) / (fromIntegral ((8*k)+x)) | k <- [0..n]]
-    -- 5000 is used in place of Infinity. This value drops off quickly, so no need to go too far.
     summation2 = [16^^(n-k) / (fromIntegral ((8*k)+x)) | k <- [(n+1)..5000]]
   in
     sum $ summation1 ++ summation2
 
-rangePi :: Maybe Integer -> Maybe Integer -> IO ()
-rangePi num1 num2 = do
-  case (num1, num2) of
-    (Just one, Just two) ->
-      if one >= two then
-        putStrLn "Please give a proper range."
-      else
-        putStrLn $ foldr (:) [] (drop (fromIntegral one) . take (fromIntegral two) $ hexDigits)
-    (_,_) -> putStrLn "Error: Please give an Integer (ex: 3) or a range (ex: 3..5)."
-
-prompt :: IO ()
-prompt = do
+
+-- Get a range of digits.
+rangePi :: (Integer -> String) -> Maybe Integer -> Maybe Integer -> String
+rangePi printFun (Just low) (Just high) =
+  if low >= high then
+    "Error: Please give a proper range."
+  else
+    foldr (++) [] (map printFun (drop (fromIntegral low) . take (fromIntegral high) $ hexDigits))
+
+rangePi _ _ _  = printErr
+
+
+prompt :: (Integer -> String) -> IO ()
+prompt printFun = do
   putStr ":: "
   hFlush stdout
   response <- getLine
@@ -41,19 +49,50 @@ prompt = do
   if (isInfixOf ".." response) then
     let
       range = splitOn ".." response
+      low = readMaybe $ range !! 0 :: Maybe Integer
+      high = readMaybe $ range !! 1 :: Maybe Integer
     in
-      rangePi (readMaybe $ range !! 0 :: Maybe Integer) (readMaybe $ range !! 1 :: Maybe Integer)
+      putStrLn $ rangePi printFun low high
     else do
       case (readMaybe response :: Maybe Integer) of
-        Nothing -> putStrLn "Error: Please give an Integer (ex: 3) or a range (ex: 3..5)."
-        Just x -> putStrLn $ hexDigits `genericIndex` x :[]
-  prompt
+        Nothing -> putStrLn printErr
+        Just x -> putStrLn $ printFun $ hexDigits `genericIndex` x
+  prompt printFun
 
--- Establish the list of answers
-hexDigits :: [Char]
+
+-- The list of answers.
+hexDigits :: [Integer]
 hexDigits = [hexPi x | x <- [0..]]
 
+
+-- Complain about argument type.
+printErr :: String
+printErr = "Error: Please give an Integer (ex: 3) or a range (ex: 3..5)."
+
+
 main :: IO ()
 main = do
-  putStrLn "Enter a digit or range (Ctrl-C to exit)"
-  prompt 
+  -- Get formatter function (hex, binary, or decimal)
+  args <- getArgs
+  let
+    printFunIO =
+      case args of
+          ["-b"] -> do
+            putStrLn "Outputting in binary."
+            return (\n -> showIntAtBase 2 (\x -> show x !! 0) n "")
+          ["-d"] -> do
+            putStrLn "Outputting in decimal."
+            return (\n -> show n ++ " ")
+          ["-h"] -> do
+            putStrLn "Generate hexadecimal Pi digits. Output in hexidemical by default.\n\
+                     \\t-b\tOutput in binary.\n\
+                     \\t-d\tOutput in decimal.\n\
+                     \\t-h\tShow this help message."
+            exitWith ExitSuccess
+          _ -> do
+            putStrLn "Outputting in hex."
+            return (\n -> showIntAtBase 16 (\x -> show x !! 0) n "")
+    in do
+      printFun <- printFunIO
+      putStrLn "Enter a digit or range (Ctrl-C to exit)."
+      prompt printFun