【今日の学び】浮動小数点の比較と関数テンプレート

double や float を == で比較するのは良くないこととされている。

内部的に2進数として扱われているため、丸め誤差が発生するからだ。

また、概念的には、整数型も浮動小数点型も比較関数でやりたいことは一緒なので、テンプレートを使いたくなる。

#include <iostream>

template <typename T>

bool comp(T a, T b){

    return a == b;

}

void printBool(bool x){

    if(x){

        std::cout << "true" << std::endl;

    }else{

        std::cout << "false" << std::endl;

    }

int main(){

    char c = 123;

    int x = 12345;

    long y = 1234567L;

    printBool(comp(c, c));

    printBool(comp(x, x));

    printBool(comp(y, y));

 

}

 これは整数型(char, short, int, long など)についてはうまく動作する。

しかし。浮動小数点も含めようとすると難しい。

浮動小数点の場合は、

 

#include <cfloat>

bool comp(double a, double b){
return std::abs(a - b) < DBL_EPSILON;
}

を使いたい。関数を直接呼ぶ場合は、引数のデータ型でうまく呼び分けてくれる。

しかし、std 内で定義されているアルゴリズムのように、比較関数を引数で受け取るようにするのが難しかった。

 

#include <iostream>
#include <cfloat>

template <typename T>
bool comp(T a, T b){
    return a == b;
}

bool comp(double a, double b){
    return std::abs(a - b) < DBL_EPSILON;
}

void printBool(bool x){
    if(x){
        std::cout << "true" << std::endl;
    }else{
        std::cout << "false" << std::endl;
    }
}

using CompF = bool (*)(double, double);
void printBool2(double a, double b, CompF f = comp){
    if(f(a, b)){
        std::cout << "true" << std::endl;
    }else{
        std::cout << "false" << std::endl;
    }
}


int main(){
    char c = 123;
    int x = 12345;
    long y = 1234567L;
    printBool(comp(c, c));
    printBool(comp(x, x));
    printBool(comp(y, y));
    printBool(comp(1.0, 1.0));
    printBool2(1.0, 1.0, comp);
    printBool2(1.0, 1.0);
}