Main.hs 3.0 KB

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