use std::env;
use num_bigint::BigUint;
use num_traits::{One, Zero};

fn main() {
    // Hämta antal decimaler från argument
    let args: Vec<String> = env::args().collect();
    let decimals: usize = if args.len() > 1 {
        args[1].parse().unwrap_or(100)
    } else {
        100
    };

    // Beräkna pi med Machins formel: pi/4 = 4*arctan(1/5) - arctan(1/239)
    // Använd num-bigint för exakt aritmetik
    let scale = BigUint::from(10u32).pow(decimals as u32 + 10);
    
    let atan1_5 = arctan_big(5u32, &scale);
    let atan1_239 = arctan_big(239u32, &scale);
    
    // 4 * atan(1/5) - atan(1/239)
    let mut result = &atan1_5 * 4u32;
    result = &result - &atan1_239;
    // * 4
    result = &result * 4u32;
    
    // Skriv ut resultatet
    println!("{}", format_pi(&result, decimals));
}

fn arctan_big(x: u32, scale: &BigUint) -> BigUint {
    // arctan(1/x) = 1/x - 1/(3*x^3) + 1/(5*x^5) - ...
    // Med skala: scale/x - scale/(3*x^3) + scale/(5*x^5) - ...
    
    let mut result = BigUint::zero();
    let x_big = BigUint::from(x);
    let x_squared = &x_big * &x_big;
    
    // term = scale / x
    let mut term = scale / &x_big;
    
    let mut sign: i32 = 1;
    let mut n: u64 = 0;
    
    loop {
        // term / (2n+1)
        let divisor = BigUint::from(2u64 * n + 1);
        let contrib = &term / &divisor;
        
        if sign > 0 {
            result = &result + &contrib;
        } else {
            result = &result - &contrib;
        }
        
        // term = term / x^2
        term = &term / &x_squared;
        
        sign = -sign;
        
        // Avbryt om termen är 0
        if term.is_zero() || n > 5000000 {
            break;
        }
        n += 1;
    }
    
    result
}

fn format_pi(pi: &BigUint, decimals: usize) -> String {
    // Konvertera till sträng
    let mut digits = pi.to_string();
    
    // Lägg till ledande noll om nödvändigt
    while digits.len() < decimals + 10 {
        digits.insert(0, '0');
    }
    
    // Ta första siffran, sedan decimalpunkt
    let int_part = &digits[0..1];
    let dec_part = &digits[1..decimals + 1];
    
    format!("{}.{}", int_part, dec_part)
}