import std/strutils
import std/os

type BigInt = object
    digits: seq[uint64]

proc initBigInt(value: int = 0): BigInt =
    if value == 0:
        result.digits = @[0'u64]
    else:
        result.digits = @[uint64(abs(value))]

proc initBigInt(value: uint64): BigInt =
    result.digits = @[value]

proc `+`(a: BigInt, b: BigInt): BigInt =
    result.digits = @[]
    var carry: uint64 = 0
    let maxLen = max(a.digits.len, b.digits.len)
    
    for i in 0..<maxLen:
        let x = if i < a.digits.len: a.digits[i] else: 0'u64
        let y = if i < b.digits.len: b.digits[i] else: 0'u64
        let sum = x + y + carry
        result.digits.add(sum mod 1_000_000_000)
        carry = sum div 1_000_000_000
    
    if carry > 0:
        result.digits.add(carry)

proc `-`(a: BigInt, b: BigInt): BigInt =
    result.digits = a.digits
    var borrow: int64 = 0
    
    for i in 0..<result.digits.len:
        let x = int64(result.digits[i])
        let y = if i < b.digits.len: int64(b.digits[i]) else: 0'i64
        var diff = x - y - borrow
        
        if diff < 0:
            diff += 1_000_000_000
            borrow = 1
        else:
            borrow = 0
        
        result.digits[i] = uint64(diff)
    
    # Remove leading zeros
    while result.digits.len > 1 and result.digits[^1] == 0:
        result.digits.delete(result.digits.len - 1)

proc `*`(a: BigInt, b: uint64): BigInt =
    result.digits = newSeq[uint64](a.digits.len)
    var carry: uint64 = 0
    
    for i in 0..<a.digits.len:
        let prod = a.digits[i] * b + carry
        result.digits[i] = prod mod 1_000_000_000
        carry = prod div 1_000_000_000
    
    if carry > 0:
        result.digits.add(carry)

proc `div`(a: BigInt, divisor: uint64): BigInt =
    result.digits = newSeq[uint64](a.digits.len)
    var remainder: uint64 = 0
    
    for i in countdown(a.digits.len - 1, 0):
        let cur = remainder * 1_000_000_000 + a.digits[i]
        result.digits[i] = cur div divisor
        remainder = cur mod divisor
    
    # Remove leading zeros
    while result.digits.len > 1 and result.digits[^1] == 0:
        result.digits.delete(result.digits.len - 1)

proc `$`(b: BigInt): string =
    result = ""
    for i in countdown(b.digits.len - 1, 0):
        if i == b.digits.len - 1:
            result.add($b.digits[i])
        else:
            result.add(align($b.digits[i], 9, '0'))

proc pow10(exp: int): BigInt =
    result = initBigInt(1)
    for i in 0..<exp:
        result = result * 10'u64

proc arctan(x: uint64, decimals: int): BigInt =
    let scale = pow10(decimals + 10)
    let xSquared = x * x
    
    var term = scale div x
    result = initBigInt(0)
    var n = 0
    
    while term.digits.len > 1 or term.digits[0] > 0:
        let divisor = uint64(2 * n + 1)
        let contrib = term div divisor
        
        if n mod 2 == 0:
            result = result + contrib
        else:
            result = result - contrib
        
        term = term div xSquared
        n += 1

proc calculatePi(decimals: int): string =
    let atan1_5 = arctan(5, decimals)
    let atan1_239 = arctan(239, decimals)
    
    # pi = 16*arctan(1/5) - 4*arctan(1/239)
    var pi = atan1_5 * 16'u64
    let pi4 = atan1_239 * 4'u64
    pi = pi - pi4
    
    let piStr = $pi
    
    # Format with decimal point
    result = "3."
    let start = 1
    var i = 0
    
    while i < decimals:
        if start + i < piStr.len:
            result.add(piStr[start + i])
        else:
            result.add('0')
        i += 1

# Main
let decimals = if paramCount() > 0:
    try:
        parseInt(paramStr(1))
    except:
        100
else:
    100

echo calculatePi(decimals)