import Foundation

// Simple BigInt implementation for arbitrary precision
class BigInt {
    var digits: [UInt64]
    
    init(_ value: Int = 0) {
        if value == 0 {
            digits = [0]
        } else {
            digits = [UInt64(abs(value))]
        }
    }
    
    init(_ value: UInt64) {
        digits = [value]
    }
    
    func add(_ other: BigInt) {
        var carry: UInt64 = 0
        let maxLen = max(digits.count, other.digits.count)
        
        for i in 0..<maxLen {
            let a = i < digits.count ? digits[i] : 0
            let b = i < other.digits.count ? other.digits[i] : 0
            let sum = a + b + carry
            
            if i < digits.count {
                digits[i] = sum % 1_000_000_000
            } else {
                digits.append(sum % 1_000_000_000)
            }
            carry = sum / 1_000_000_000
        }
        
        if carry > 0 {
            digits.append(carry)
        }
    }
    
    func subtract(_ other: BigInt) {
        var borrow: Int64 = 0
        
        for i in 0..<digits.count {
            let a = Int64(digits[i])
            let b = i < other.digits.count ? Int64(other.digits[i]) : 0
            var diff = a - b - borrow
            
            if diff < 0 {
                diff += 1_000_000_000
                borrow = 1
            } else {
                borrow = 0
            }
            
            digits[i] = UInt64(diff)
        }
        
        // Remove leading zeros
        while digits.count > 1 && digits.last! == 0 {
            digits.removeLast()
        }
    }
    
    func multiply(_ other: BigInt) -> BigInt {
        let result = BigInt()
        result.digits = Array(repeating: 0, count: digits.count + other.digits.count)
        
        for i in 0..<digits.count {
            var carry: UInt64 = 0
            for j in 0..<other.digits.count {
                let prod = digits[i] * other.digits[j] + result.digits[i + j] + carry
                result.digits[i + j] = prod % 1_000_000_000
                carry = prod / 1_000_000_000
            }
            if carry > 0 {
                result.digits[i + other.digits.count] += carry
            }
        }
        
        // Remove leading zeros
        while result.digits.count > 1 && result.digits.last! == 0 {
            result.digits.removeLast()
        }
        
        return result
    }
    
    func divide(_ divisor: UInt64) -> BigInt {
        let result = BigInt()
        result.digits = Array(repeating: 0, count: digits.count)
        
        var remainder: UInt64 = 0
        for i in (0..<digits.count).reversed() {
            let cur = remainder * 1_000_000_000 + digits[i]
            result.digits[i] = cur / divisor
            remainder = cur % divisor
        }
        
        // Remove leading zeros
        while result.digits.count > 1 && result.digits.last! == 0 {
            result.digits.removeLast()
        }
        
        return result
    }
    
    func toString() -> String {
        var result = ""
        for i in (0..<digits.count).reversed() {
            if i == digits.count - 1 {
                result += String(digits[i])
            } else {
                result += String(format: "%09d", digits[i])
            }
        }
        return result
    }
}

func pow10(_ exp: Int) -> BigInt {
    let result = BigInt(1)
    for _ in 0..<exp {
        let temp = result.multiply(BigInt(10))
        result.digits = temp.digits
    }
    return result
}

func arctan(_ x: UInt64, decimals: Int) -> BigInt {
    let scale = pow10(decimals + 10)
    let xSquared = x * x
    
    var term = scale.divide(x)
    var result = BigInt(0)
    var n = 0
    
    while term.digits.count > 1 || term.digits[0] > 0 {
        let divisor = UInt64(2 * n + 1)
        let contrib = term.divide(divisor)
        
        if n % 2 == 0 {
            result.add(contrib)
        } else {
            result.subtract(contrib)
        }
        
        term = term.divide(xSquared)
        n += 1
    }
    
    return result
}

func calculatePi(_ decimals: Int) -> String {
    let atan1_5 = arctan(5, decimals: decimals)
    let atan1_239 = arctan(239, decimals: decimals)
    
    // pi = 16*arctan(1/5) - 4*arctan(1/239)
    let pi16 = atan1_5.multiply(BigInt(16))
    let pi4 = atan1_239.multiply(BigInt(4))
    pi16.subtract(pi4)
    
    let piStr = pi16.toString()
    
    // Format with decimal point
    var result = "3."
    let start = piStr.index(piStr.startIndex, offsetBy: 1)
    let digits = piStr[start...]
    
    var i = 0
    for char in digits {
        if i >= decimals { break }
        result.append(char)
        i += 1
    }
    
    // Pad with zeros if needed
    while i < decimals {
        result.append("0")
        i += 1
    }
    
    return result
}

// Main
let decimals: Int
if CommandLine.arguments.count > 1 {
    decimals = Int(CommandLine.arguments[1]) ?? 100
} else {
    decimals = 100
}

let pi = calculatePi(decimals)
print(pi)