module Main where

import System.Environment (getArgs)
import Data.Char (digitToInt)

-- Calculate arctan(1/x) using Taylor series
-- arctan(1/x) = 1/x - 1/(3*x^3) + 1/(5*x^5) - ...
arctan :: Integer -> Integer -> Integer
arctan x decimals = arctanIter scale xSquared term 0 0
  where
    scale = 10 ^ (decimals + 10)
    xSquared = x * x
    term = scale `div` x  -- First term: scale / x
    
    arctanIter :: Integer -> Integer -> Integer -> Integer -> Integer -> Integer
    arctanIter scale xSquared term n result
      | term == 0 || n > decimals * 3 = result
      | otherwise = arctanIter scale xSquared newTerm (n + 1) newResult
      where
        divisor = 2 * n + 1
        contrib = term `div` divisor
        newResult = if even n
                     then result + contrib
                     else result - contrib
        newTerm = term `div` xSquared  -- Divide by x² each iteration

-- Calculate pi using Machin's formula
-- pi/4 = 4*arctan(1/5) - arctan(1/239)
calculatePi :: Integer -> Integer
calculatePi decimals = 16 * atan1_5 - 4 * atan1_239
  where
    atan1_5 = arctan 5 decimals
    atan1_239 = arctan 239 decimals

-- Format pi with decimal point
formatPi :: Integer -> Integer -> String
formatPi pi decimals = "3." ++ take (fromIntegral decimals) (drop 1 (show pi))

main :: IO ()
main = do
  args <- getArgs
  let decimals = case args of
                   [] -> 100
                   (x:_) -> case reads x :: [(Integer, String)] of
                              [(d, _)] -> if d > 0 then d else 100
                              _ -> 100
  
  let pi = calculatePi decimals
  putStrLn (formatPi pi decimals)