
//
//  mint.hpp 四則演算テスト
//
//  mint has: 34512  <- ここと
//  expected: 34512  <- ここに表示される数値が一致していればOK，というテスト
//

#include <iostream>
#include <string>

#include "mint.hpp"

using namespace std;


template <class Mint>
string to_string (const Mint& bignum) {

  string result;

  if (! bignum)
    result = "0";
  else {
    const unsigned int denomi = 1000000000; // 適当に大きな 10^n の数
    char buf[11];
    string fragment;
    Mint temp1, temp2 = bignum;

    while (temp2) {
      temp1 = temp2 % denomi;
      fragment = temp1.c_str(buf, sizeof(buf));
      result.insert(0, fragment);
      temp2 /= denomi;

      // ゼロサプレスするべき？
      if (temp2) {
        // assert (fragment.length() <= 9);
        result.insert(0, 9 - fragment.length(), '0'); // 9 は denomi の 0 の個数
      }

    }
  }

  return result;
}

const char *title = "";
void comp_disp (const MultiInteger<4>& mint, const char *disp) {
  string mint_str = to_string(mint);
  cout << title << endl;
  cout << " mint has: " << mint_str << endl;
  cout << " expected: " << disp << endl;
  cout << (mint_str == disp ? " ok." : " failed.") << endl;
}


//=============================================================================
void test_add () {
  cout << "-- test operator + ()" << endl;
  MultiInteger<4> mint1, mint2;

 //------------
 title  = "test 1";
  mint1 = "98765432187654321";
  mint2 = " 1234567812345679";
  comp_disp (mint1 + mint2, "100000000000000000");

 //-----------------
 title = "test 2";
  mint1 =          "980065";
  comp_disp (mint1 + 20035, "1000100");


 //----------------
 title = "test 3";
  mint1 = "980065";
  comp_disp (20035 + mint1, "1000100");
}


//=============================================================================
void test_sub () {
  cout << "-- test operator - ()" << endl;
  MultiInteger<4> mint1, mint2;

 //---------------
 title = "test 1";
  mint1 = "100000000100000000";
  mint2 = "   200000000050000";
  comp_disp (mint1 - mint2, "99800000099950000");

 //------------------
 title = "test 2";
  mint1 = "20000000000000000000000000";
  comp_disp (mint1 - 8, "19999999999999999999999992");

 //----------------------
 title = "test 3";
  mint1 = 1;
  comp_disp (0 - mint1, "340282366920938463463374607431768211455");
    // この数の検算は，Mint にこの数を食わせ，c_str() で16進数表記で出力し
    // F が 8x4=32個出力された事を確認しただけ。
}


//=============================================================================
void test_mul () {
  cout << "-- test operator * ()" << endl;
  MultiInteger<4> mint1, mint2;

 //----------------
 title = "test 1";
  mint1 = "1234567890";
  mint2 = "1234567890";
  comp_disp (mint1 * mint2, "1524157875019052100");

 //-----------------
 title = "test 2";
  mint1 = "1234567890";
  comp_disp (mint1 * 123456789, "152415787501905210");

 //-----------------
 title = "test 3";
  mint1 = "1234567890";
  comp_disp (123456789 * mint1, "152415787501905210");
}

//=============================================================================
void test_div () {
  cout << "-- test operator / ()" << endl;
  MultiInteger<4> mint1, mint2;

 //------------
 title = "test 1";
  mint1 = "1524157875019052109";
  mint2 = "1234567890";
  comp_disp (mint1 / mint2, "1234567890");

 //-----------------
 title = "test 2";
  mint1 = "152415787501905219";
  comp_disp (mint1 / 123456789, "1234567890");

 //------------------
 title = "test 3";
  mint1 = 12345;
  comp_disp (152399025 / mint1, "12345");
}


//=============================================================================
void test_mod () {
  cout << "-- test operator % ()" << endl;
  MultiInteger<4> mint1, mint2;

 //-------------
 title = "test 1";
  mint1 = "1524157875019052109";
  mint2 = "1234567890";
  comp_disp (mint1 % mint2, "9");

 //---------------
 title = "test 2";
  mint1 = "152415787625361998";
  comp_disp (mint1 % 123456789, "123456788");

 //-----------------
 title = "test 3";
  mint1 = 12345;
  comp_disp (152411369 % mint1, "12344");

}

int main (int argc, char *argv[]) {
  try {
    test_add();
    test_sub();
    test_mul();
    test_div();
    test_mod();

  } catch (const char *msg) {
    cout << "exception: " << msg << endl;

  } catch (...) {
    cout << "unknoown exception." << endl;
  }

  return 0;
}


