#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>

#define K 10000
#define M 2501   // 4*(M-1)=小数点以下の桁数 (10 進)
#define N 2078   // 4*(N-1)=小数点以下の桁数 (16 進)
                // M-1≒1.204 (N-1)

void Add(unsigned a[], unsigned b[]);
void Sub(unsigned a[], unsigned b[]);
void Div(unsigned a[], unsigned d);
void Mul(unsigned a[], unsigned d);
void Dup(unsigned a[], unsigned b[]);
void ATAN(unsigned x[], int m);
int if_zero(unsigned a[]);
void Display(unsigned a[]);
void to_decimal(unsigned a[], unsigned w[]);



int main(){
    unsigned x[N], y[N];

    ATAN(x, 5);
    Mul(x, 4);

    ATAN(y, 239);

    Sub(x, y);
    Mul(x, 4);

    Display(x);
    return 0;
}

void ATAN(unsigned x[], int m){
    int i, e;
    unsigned m2;
    unsigned y[N], z[N];
    for(i = 0; i < N; i++){     // 配列 x,y の初期化
        x[i] = 0;
        y[i] = 0;
    }
    y[0] = 1;

    Div(y, m);
    Dup(y, x);
    m2 = m*m;
    i = 1;
    do {
        Div(y, m2);
        Dup(y, z);
        Div(z, 2*i+1);
        if( (i & 1) == 0 ){     // i が偶数のとき
            Add(x, z);
        } else {                // i が奇数のとき
            Sub(x, z);
        }
        i++;
        e = if_zero(z);         // z が 0 でないと -1
    } while (e == -1);          // z が 0 でない限り継続
    
}

//足算,  a + b を a に代入
void Add(unsigned a[], unsigned b[]){
    int i,j;
    unsigned x;
    for(i = 0; i < N; i++){
        x = a[i] + b[i];
        if(x <= 0xffff){            // 桁上がりしないとき
            a[i] = x;
        } else {                    // 桁上がりするとき
            a[i] = x & 0xffff;      // x の下位 2 バイト
            j = i-1;                // 以下桁上がりの操作
            while(a[j] == 0xffff){  // 1 加えると更に桁が上がるとき
                a[j] = 0;
                j--;
            }
            a[j]++;
        }
    }
}

//引き算,  a - b を a  に代入 (但し a>b)
void Sub(unsigned a[], unsigned b[]){
    int i,j;
    for(i = 0; i < N; i++){
        if (a[i] >= b[i]){                  // そのまま引けるとき
            a[i] = a[i] - b[i];
        } else {                            // 上の桁から借りるとき
            a[i] = 0x10000 + a[i] - b[i];   // 1 を上から借りる
            j = i-1;
            while(a[j] == 0){               // 上の桁が 0 であれば
                a[j] = 0xffff;              // 更に上から借りる
                j--;
            }
            a[j]--;
        }
    }

}

//割り算,  a/d を a に代入 (d <= 0xffff, 16 進 4桁)
// 上の桁から順番に d で割り算。
void Div(unsigned a[], unsigned d){
    int i;
    unsigned x, q, res;
    res = 0;
    for(i = 0; i < N; i++){
        res = res << 16;        // 上の桁の余りを 16 進で4 桁ずらして
        x = a[i] + res;         // 加える
        q = x/d;                // d でわる
        a[i] = q;               // 商
        res = x - q*d;          // 余りは下の桁の割り算に加える
    }
}

//かけ算, a*d を a に代入 (d <= 0xffff, 16 進 4 桁)
// 下の桁から順番に d をかける。
void Mul(unsigned a[], unsigned d){
    int i; 
    unsigned x, q;
    q = 0;
    for(i = N-1; i >= 0; i--){
        x = a[i]*d + q;         // 各桁の d 倍に桁上がりの部分を加える
        a[i] = x & 0xffff;      // x の下位 2 バイト (16 進 4 桁)
        q = x >> 16;            // x の上位 2 バイト (16 進 4 桁)
    }                           // 桁上がりの部分
}

//a を b にコピー
void Dup(unsigned a[], unsigned b[]){
    int i;
    for(i = 0; i < N; i++){
        b[i] = a[i];
    }
}

// a = 0 のとき 0 を返し、そうでないとき -1 を返す関数
int if_zero(unsigned a[]){
    int i, j;
    j = 0;
    for(i = 0; i < N; i++){
        if (a[i] != 0) {            // 一箇所でも 0 でないとき
            j = -1;                 // j の値を -1 にする
            break;
        }
    }
    return j;
}

//  10 進数に変換して表示
void Display(unsigned a[]){
    int i,j;
    unsigned w[M];
    char buf[K+1] = "";
    char tmp[16];
    to_decimal(a, w);               // 16 進数 a を 10 進数 w に変換
    for(i = 1; i < M; i++){
        sprintf(tmp, "%4.4u", w[i]);// 4 桁ごとバッファに格納
        strcat(buf, tmp);
    }
    printf("%4.1u.",w[0]);          // 小数点以上の表示
    for(i = 0; i < K/5; i++){
        printf("%-.5s ", buf+i*5);  // 5 桁ごと表示
        j = i%10;                   // j は i を 10 で割った余り
        if(j==10-1) printf("\n     "); // 10 個表示したとき改行
    }
    printf("\n");                   // 一番最後に改行
}

//  10 進数への変換
void to_decimal(unsigned a[], unsigned w[]){
    int i;
    unsigned b[N];
    for(i = 0; i < N; i++){
        b[i] = a[i];
    }
    w[0] = b[0];
    b[0] = 0;
    for(i = 1; i < M; i++){
        Mul(b, 10000);              // b を 10000 倍して
        w[i] = b[0];                // 小数点以上を w[i] に代入
        b[0] = 0;                   // 小数点以上を 0 にする
    }
}
