丸め誤差
丸め誤差
小数点以下の数は2進数で表現できないため近似値を使用している。
例えば"0.1(10)"は"0.0001100110011...(2)"となり、"0011"が永遠に循環する。
このため、適当な桁で結果が偶数になるように丸める(最近接偶数への丸め)。
以上から発生する誤差が丸め誤差。
COBOLでは丸め誤差は発生しない。
public static double GetByDoubleVariant()
{
var a = 0.1;
var b = 0.1;
var c = 2.5;
return (a * b) / c; // 0.004000000000000001
}
対処法
整数型で計算
整数型に変換して、計算を行う。 ただし、小数に10n倍しただけでは整数になっていない可能性もあるので、Math.Roundメソッドを使う。
public static double GetByDoubleConvIntVariant()
{
var a = 0.1;
var b = 0.1;
var c = 2.5;
var aInt = Math.Round(a * 10, MidpointRounding.AwayFromZero);
var bInt = Math.Round(b * 10, MidpointRounding.AwayFromZero);
var cInt = Math.Round(c * 10, MidpointRounding.AwayFromZero);
return ((aInt * bInt) / cInt) / 10; // 0.004
}
任意精度型を使用
C#ではDecimal型が該当する。ただしパフォーマンスが悪い。
public static decimal GetByDecimalVariant()
{
var a = 0.1m;
var b = 0.1m;
var c = 2.5m;
return (a * b) / c;
}