小数点以下1桁の計算を行うクラス・演算子オーバーロードの実験

スポンサーリンク
スポンサーリンク
ライフスタイル関連のコンテンツ
お金 | 仕事 | 勉強 | プライベート | 健康 |
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般

演算子オーバーロードの実験として、小数点以下1桁にそろえて乗算の計算結果を返すクラスを作ってみました。

スポンサーリンク

#include <iostream>
#include <assert.h>
#include <stdlib.h>
 
// 内部的に小数点以下1桁の数字を整数で保持するために10を掛ける
const int digit = 10;
 
/*********************************************************************
* 倍精度浮動小数点数を小数点以下1桁にするために加算する補正数字
* 浮動小数点数1.5は、コンピュータ内では1.4999999999...で保持されるため、
* 小数点以下2桁を切り捨てると1.4になってしまう。
* この問題を避けるために、補正係数として0.0001を足す
*********************************************************************/
const double correct_num = 0.0001;
 
/*********************************************************************
* ptoneクラス
* 乗算で小数点以下を1桁に固定するクラス
* 
* オーバーロードする演算子をメンバ関数で定義
*    f -- 固定小数点数
*    s -- double型小数点数
* 
* // 乗算
* f = f * f;
* f = s * f;
* f = f * s;
*
* ostream << f    // 出力
*********************************************************************/
class ptone {
private:
    // 固定小数点の値(digit(10)をかけて内部的には整数で保持する)
    long int number;
 
    // double型を小数点以下1桁に変更する静的メンバ関数
    static long int double2ptone(const double num_double) {
        return (
            static_cast<long int>(                // 4. 最終的にlong int型にキャスト
                num_double                        // 1. double型の浮動小数点数
                * static_cast<double>(digit)    // 2. digit(10)をdouble型にキャスト後かける
                + correct_num                    // 3. 補正係数を足す
            )
        );
    }
 
public:
    // デフォルトコンストラクタ
    ptone() {
        number = 0;        // numberを0にする
    }
 
    // コピーコンストラクタ
    ptone(const ptone& old_ptone) {
        number = old_ptone.number;    // numberをold_ptone.numberにする
    }
    
    // doubleからptoneを生成。コンストラクタのオーバーロード
    ptone(const double num_real) {
        number = double2ptone(num_real);
    }
 
    // デストラクタ。何もしない。
    ~ptone() {
    }
 
    /****************************
    * メンバ関数を定義
    ****************************/
    
    // 数値を設定する
    void set(const double real) {
        number = double2ptone(real);
    }
 
    // 数値を取得。digit(10)で割る
    double get() const {
        return (static_cast<double>(number) / digit);
    }
 
private:
    // 内部変換
    ptone(const long int value) : number(value) {}
 
    // 乗算。* 演算子のオーバーロード
    friend ptone operator * (const ptone& ope1, const ptone& ope2);
    friend ptone operator * (const ptone& ope1, const double ope2);
    friend ptone operator * (const double ope1, const ptone& ope2);
 
    // 出力演算子 << のオーバーロード
    friend std::ostream& operator << (std::ostream& out, const ptone& numobj);
};
 
// 乗算。* 演算子のオーバーロード
ptone operator * (const ptone& ope1, const ptone& ope2) {
    return ptone(ope1.number * ope2.number / digit);
}
 
ptone operator * (const ptone& ope1, const double ope2) {
    return ptone(ope1.number * ptone::double2ptone(ope2) / digit);
}
 
ptone operator * (const double ope1, const ptone& ope2) {
    return ptone(ptone::double2ptone(ope1) * ope2.number / digit);
}
 
// 出力演算子 << のオーバーロード
std::ostream& operator << (std::ostream& out, const ptone& numobj) {
    long int before_dp = numobj.number / digit;        // 小数点の前部分
    long int after_dp = abs(numobj.number % digit);    // 小数点以下1桁目
    out << before_dp << '.' << after_dp;            // 整形して1桁小数点数を出力
    return (out);
}
 
// テスト用ルーチン
int main() {
    ptone result_a(2.3 * 4.682);    // 10.7 が期待される
    ptone result_b(0.00005 * 3);    // 0.0 が期待される
    ptone result_c(3.0 * 4);            // 12.0 が期待される
    std::cout << result_a << std::endl;
    std::cout << result_b << std::endl;
    std::cout << result_c << std::endl;
    std::cout << result_a * result_c << std::endl;    // 128.4 が期待される
 
    return 0;
}
 

テスト用ルーチンのとおり、* 演算子はオーバーロードされていますので、計算結果では小数点以下が1桁にフォーマットされて出力されるはずです。

実行結果。

10.7
0.0
12.0
128.4

ちゃんと出力されました。

演算子のオーバーロードは、いろいろな演算子で可能ですので、必要となったら後学することにします。
以下のページがとても分かりやすい。

参考:
C++マニアック,オペレータのオーバーロード,operator overload,演算子のオーバーロード,演算子

スポンサーリンク
 
スポンサーリンク