//  有理数クラスサンプルプログラム  --------------------------------------------//

//  (C) Copyright Paul Moore 1999. Permission to copy, use, modify, sell
//  and distribute this software is granted provided this copyright notice
//  appears in all copies. This software is provided "as is" without express or
//  implied warranty, and with no claim as to its suitability for any purpose.

//  履歴
//  14 Dec 99  Initial version

#include <iostream>
#include <cassert>
#include <cstdlib>
#include <boost/config.hpp>
#ifndef BOOST_NO_LIMITS
#include <limits>
#else
#include <limits.h>
#endif
#include <exception>
#include <boost/rational.hpp>

using std::cout;
using std::endl;
using boost::rational;

#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
// これは MSVC が、"Koenig Kookup" をサポートしていないために必要になるあまり美しくないハックである。
// C++ スタンダードによれば、abs(r) の呼び出しに際して、コンパイラは、abs() の定義を、r が属する
// 名前空間を（この場合は、boost である）含めて探さなければならない。

// Koening Lookup は、比較的最近追加された機能であり、これをサポートしていないコンパイラもある
// その場合は、この行を追加してみてほしい

using boost::abs;
#endif

int main ()
{
    rational<int> half(1,2);
    rational<int> one(1);
    rational<int> two(2);

    // 基本的なチェック
    assert(half.numerator() == 1);
    assert(half.denominator() == 2);
    assert(boost::rational_cast<double>(half) == 0.5);

    // 数値演算
    assert(half + half == one);
    assert(one - half == half);
    assert(two * half == one);
    assert(one / half == two);

    // 整数型への型変換
    assert(half+half == 1);
    assert(2 * half == one);
    assert(2 * half == 1);
    assert(one / half == 2);
    assert(1 / half == 2);

    // 符号処理
    rational<int> minus_half(-1,2);
    assert(-half == minus_half);
    assert(abs(minus_half) == half);

    // オーバーフローの回避可否チェック
#ifndef BOOST_NO_LIMITS
    int maxint = std::numeric_limits<int>::max();
#else
    int maxint = INT_MAX;
#endif
    rational<int> big(maxint, 2);
    assert(2 * big == maxint);

    // 上記の結果を表示する
    cout << half << "+" << half << "=" << one << endl;
    cout << one << "-" << half << "=" << half << endl;
    cout << two << "*" << half << "=" << one << endl;
    cout << one << "/" << half << "=" << two << endl;
    cout << "abs(" << minus_half << ")=" << half << endl;
    cout << "2 * " << big << "=" << maxint
	 << " (rational: " << rational<int>(maxint) << ")" << endl;

    // 追加
    rational<int> pi(22,7);
    cout << "pi = " << boost::rational_cast<double>(pi) << " (nearly)" << endl;

    // 例外のハンドリング
    try {
        rational<int> r;        // 初期値を設定しなかった―０になってしまう。
        r = 1/r;                // しまった！
    }
    catch (const boost::bad_rational &e) {
        cout << "Bad rational, as expected: " << e.what() << endl;
    }
    catch (...) {
	cout << "Wrong exception raised!" << endl;
    }

    return 0;
}

