【今日の学び】浮動小数点の比較と関数テンプレート
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);
}