Main.hs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. module Main where
  2. import Numeric (showHex, showIntAtBase)
  3. import Data.List (isInfixOf, genericIndex)
  4. import Data.List.Split(splitOn)
  5. import Text.Read (readMaybe)
  6. import System.IO (hFlush, stdout)
  7. import System.Environment (getArgs)
  8. import System.Exit (exitWith, ExitCode(ExitSuccess))
  9. import Control.Parallel
  10. -- Get the hex representation of Pi at place n.
  11. hexPi :: Integer -> Integer
  12. hexPi n =
  13. let
  14. summation = let
  15. sone = (4 * sumPi n 1)
  16. sfour = (2 * sumPi n 4)
  17. sfive = (sumPi n 5)
  18. ssix = (sumPi n 6)
  19. in
  20. sone `par` sfour `par` sfive `par` ssix `par` sone - sfour - sfive - ssix
  21. skimmedSum = summation - (fromIntegral (floor summation :: Integer)) -- Take only the decimal portion
  22. in
  23. floor (16 * skimmedSum) :: Integer
  24. -- Calculate the summation.
  25. -- 5000 is used in place of Infinity. This value drops off quickly, so no need to go too far.
  26. sumPi :: Integer -> Integer -> Double
  27. sumPi n x =
  28. let
  29. summation1 = [(fromIntegral ((16^(n-k) `mod` ((8*k)+x)))) / (fromIntegral ((8*k)+x)) | k <- [0..n]]
  30. summation2 = [16^^(n-k) / (fromIntegral ((8*k)+x)) | k <- [(n+1)..5000]]
  31. in
  32. sum $ summation1 ++ summation2
  33. -- Get a range of digits.
  34. rangePi :: (Integer -> String) -> Maybe Integer -> Maybe Integer -> String
  35. rangePi printFun (Just low) (Just high) =
  36. if low >= high then
  37. "Error: Please give a proper range."
  38. else
  39. foldr (++) [] (map printFun (drop (fromIntegral low) . take (fromIntegral high) $ hexDigits))
  40. rangePi _ _ _ = printErr
  41. prompt :: (Integer -> String) -> IO ()
  42. prompt printFun = do
  43. putStr ":: "
  44. hFlush stdout
  45. response <- getLine
  46. -- Check if response is range, or single digit.
  47. if (isInfixOf ".." response) then
  48. let
  49. range = splitOn ".." response
  50. low = readMaybe $ range !! 0 :: Maybe Integer
  51. high = readMaybe $ range !! 1 :: Maybe Integer
  52. in
  53. putStrLn $ rangePi printFun low high
  54. else do
  55. case (readMaybe response :: Maybe Integer) of
  56. Nothing -> putStrLn printErr
  57. Just x -> putStrLn $ printFun $ hexDigits `genericIndex` x
  58. prompt printFun
  59. -- The list of answers.
  60. hexDigits :: [Integer]
  61. hexDigits = [hexPi x | x <- [0..]]
  62. -- Complain about argument type.
  63. printErr :: String
  64. printErr = "Error: Please give an Integer (ex: 3) or a range (ex: 3..5)."
  65. main :: IO ()
  66. main = do
  67. -- Get formatter function (hex, binary, or decimal)
  68. args <- getArgs
  69. let
  70. printFunIO =
  71. case args of
  72. ["-b"] -> do
  73. putStrLn "Outputting in binary."
  74. return (\n -> showIntAtBase 2 (\x -> show x !! 0) n "")
  75. ["-d"] -> do
  76. putStrLn "Outputting in decimal."
  77. return (\n -> show n ++ " ")
  78. ["-h"] -> do
  79. putStrLn "Generate hexadecimal Pi digits. Output in hexidemical by default.\n\
  80. \\t-b\tOutput in binary.\n\
  81. \\t-d\tOutput in decimal.\n\
  82. \\t-h\tShow this help message."
  83. exitWith ExitSuccess
  84. _ -> do
  85. putStrLn "Outputting in hex."
  86. return (\n -> showHex n "")
  87. in do
  88. printFun <- printFunIO
  89. putStrLn "Enter a digit or range (Ctrl-C to exit)."
  90. prompt printFun