#include <iostream>
#include <cstdlib>
#include <string>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>

namespace mp = boost::multiprecision;

// Calculate arctan(1/x) using Taylor series with arbitrary precision
// arctan(1/x) = 1/x - 1/(3*x^3) + 1/(5*x^5) - ...
mp::cpp_int arctan(unsigned long x, unsigned long decimals) {
    // Scale factor: 10^(decimals + 10) for precision
    mp::cpp_int scale = mp::pow(mp::cpp_int(10), decimals + 10);
    
    mp::cpp_int result = 0;
    mp::cpp_int x_big = x;
    mp::cpp_int x_squared = x_big * x_big;
    
    // First term: scale / x
    mp::cpp_int term = scale / x_big;
    
    int sign = 1;
    unsigned long n = 0;
    
    // Iterate through Taylor series
    // term_n = scale / ((2n+1) * x^(2n+1))
    // But we compute iteratively: term = term / x^2 each iteration
    while (term != 0 && n < decimals * 3) {
        // Divide by (2n+1)
        mp::cpp_int contrib = term / (2 * n + 1);
        
        if (sign > 0) {
            result += contrib;
        } else {
            result -= contrib;
        }
        
        // Next term: divide by x^2
        term /= x_squared;
        
        sign = -sign;
        n++;
        
        // Stop when term becomes negligible
        if (n > decimals * 2) break;
    }
    
    return result;
}

// Calculate pi using Machin's formula
// pi/4 = 4*arctan(1/5) - arctan(1/239)
mp::cpp_int calculate_pi(unsigned long decimals) {
    mp::cpp_int arctan_1_5 = arctan(5, decimals);
    mp::cpp_int arctan_1_239 = arctan(239, decimals);
    
    // pi = 16*arctan(1/5) - 4*arctan(1/239)
    mp::cpp_int pi = 16 * arctan_1_5 - 4 * arctan_1_239;
    
    return pi;
}

int main(int argc, char *argv[]) {
    unsigned long decimals = 100;
    
    if (argc > 1) {
        decimals = std::strtoul(argv[1], nullptr, 10);
        if (decimals == 0) {
            decimals = 100;
        }
    }
    
    mp::cpp_int pi = calculate_pi(decimals);
    
    // Convert to string
    std::string pi_str = pi.convert_to<std::string>();
    
    // Print with decimal point
    if (!pi_str.empty()) {
        std::cout << '3';
        if (decimals > 0) {
            std::cout << '.';
            // Print decimals, skipping the leading "3"
            size_t start = 1;
            size_t end = start + decimals;
            if (end > pi_str.length()) end = pi_str.length();
            for (size_t i = start; i < end && i < pi_str.length(); i++) {
                std::cout << pi_str[i];
            }
        }
        std::cout << '\n';
    }
    
    return 0;
}