Main.hs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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 = sum [(fromIntegral ((16^(n-k) `mod` ((8*k)+x)))) / (fromIntegral ((8*k)+x)) | k <- [0..n]]
  30. summation2 = sum [16^^(n-k) / (fromIntegral ((8*k)+x)) | k <- [(n+1)..5000]]
  31. in
  32. 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. -- foldl (.) id (map (showString . printFun) (drop (fromIntegral low) . take (fromIntegral high) $ hexDigits)) "" -- Alternative implementation: not sure about speed
  41. rangePi _ _ _ = printErr
  42. prompt :: (Integer -> String) -> IO ()
  43. prompt printFun = do
  44. putStr ":: "
  45. hFlush stdout
  46. response <- getLine
  47. -- Check if response is range, or single digit.
  48. if (isInfixOf ".." response) then
  49. let
  50. range = splitOn ".." response
  51. low = readMaybe $ range !! 0 :: Maybe Integer
  52. high = readMaybe $ range !! 1 :: Maybe Integer
  53. in
  54. putStrLn $ rangePi printFun low high
  55. else do
  56. case (readMaybe response :: Maybe Integer) of
  57. Nothing -> putStrLn printErr
  58. Just x -> putStrLn $ printFun $ hexDigits `genericIndex` x
  59. prompt printFun
  60. -- The list of answers.
  61. hexDigits :: [Integer]
  62. hexDigits = [hexPi x | x <- [0..]]
  63. -- Complain about argument type.
  64. printErr :: String
  65. printErr = "Error: Please give an Integer (ex: 3) or a range (ex: 3..5)."
  66. main :: IO ()
  67. main = do
  68. -- Get formatter function (hex, binary, or decimal)
  69. args <- getArgs
  70. let
  71. printFunIO =
  72. case args of
  73. ["-b"] -> do
  74. putStrLn "Outputting in binary."
  75. return (\n -> showIntAtBase 2 (\x -> show x !! 0) n "")
  76. ["-d"] -> do
  77. putStrLn "Outputting in decimal."
  78. return (\n -> show n ++ " ")
  79. ["-h"] -> do
  80. putStrLn "Generate hexadecimal Pi digits. Output in hexidemical by default.\n\
  81. \\t-b\tOutput in binary.\n\
  82. \\t-d\tOutput in decimal.\n\
  83. \\t-h\tShow this help message."
  84. exitWith ExitSuccess
  85. _ -> do
  86. putStrLn "Outputting in hex."
  87. return (\n -> showHex n "")
  88. in do
  89. printFun <- printFunIO
  90. putStrLn "Enter a digit or range (Ctrl-C to exit)."
  91. prompt printFun