第一次遇到浮点运算精度不够的问题
写了这么久程序,第一次受困于浮点运算精度不够的问题。比如下面的代码:
像 100.85-100.5=0.35 这么一目了然的操作,计算的结果却是0.349999999999994,导致我一个绘图的程序结果总是少一个点。查了些资料,IBM 网站上Brian Goetz 的这篇《您的小数点到哪里去了?》讲的比较清楚:计算机处理整型值很精确,但处理小数时用 float 或 double 浮点类型就会有误差了,而且这是不可避免的。
后来我采用的解决办法是把 double 类型的值放大 10000 倍,然后转成 long 长整型,中间计算过程全部用 long 型,最后把计算结果再转回 double 型并除以 10000 得到最终运算结果。之所以选择 10000 作为比例因子是因为我所有值的小数点后都不超过4位。这样就解决了利用 double 型产生的误差问题。之后我又用Decimal 类型作测试,把 double 转成 Decimal 再计算,结果也没有错误。MSDN 中讲“Decimal 值类型适用于要求使用大量有效的整数及小数位数并且没有舍入错误的财务计算”,看来把 double 转成 Decimal 是 .Net 中避免浮点运算误差比较正的路子。
记得刚开始学 C# 时,公司的师傅给的“C#编码规范”中有句话“不要比较浮点数的相等,如:10.0*0.1==1.0,不可靠”。当时还不理解,10.0*0.1=1.0天经地义,咋会不可靠呢?今天知道了,电脑还是不如人脑好使。
相关资料:
大坏蛋 数据类型的BUG还是???
Kathleen Dollard 正确运用数据类型
public static void DoubleTest()
{
double value1 = 100.85;
double value2 = 100.5;
double divisor = 0.025;
double difference = value1 - value2;
double mod = difference % divisor;
double quotient = difference / divisor;
Console.WriteLine( "=================DoubleTest=================" );
Console.WriteLine( "{0, -32} : {1}", "value1", value1 );
Console.WriteLine( "{0, -32} : {1}", "value2", value2 );
Console.WriteLine( "{0, -32} : {1}", "divisor", divisor );
Console.WriteLine( "{0, -32} : {1}", "difference = value1 - value2", difference );
Console.WriteLine( "{0, -32} : {1}", "mod = difference % divisor", mod );
Console.WriteLine( "{0, -32} : {1}", "quotient = differenct / divisor", quotient );
Console.WriteLine();
}
{
double value1 = 100.85;
double value2 = 100.5;
double divisor = 0.025;
double difference = value1 - value2;
double mod = difference % divisor;
double quotient = difference / divisor;
Console.WriteLine( "=================DoubleTest=================" );
Console.WriteLine( "{0, -32} : {1}", "value1", value1 );
Console.WriteLine( "{0, -32} : {1}", "value2", value2 );
Console.WriteLine( "{0, -32} : {1}", "divisor", divisor );
Console.WriteLine( "{0, -32} : {1}", "difference = value1 - value2", difference );
Console.WriteLine( "{0, -32} : {1}", "mod = difference % divisor", mod );
Console.WriteLine( "{0, -32} : {1}", "quotient = differenct / divisor", quotient );
Console.WriteLine();
}
后来我采用的解决办法是把 double 类型的值放大 10000 倍,然后转成 long 长整型,中间计算过程全部用 long 型,最后把计算结果再转回 double 型并除以 10000 得到最终运算结果。之所以选择 10000 作为比例因子是因为我所有值的小数点后都不超过4位。这样就解决了利用 double 型产生的误差问题。之后我又用Decimal 类型作测试,把 double 转成 Decimal 再计算,结果也没有错误。MSDN 中讲“Decimal 值类型适用于要求使用大量有效的整数及小数位数并且没有舍入错误的财务计算”,看来把 double 转成 Decimal 是 .Net 中避免浮点运算误差比较正的路子。
记得刚开始学 C# 时,公司的师傅给的“C#编码规范”中有句话“不要比较浮点数的相等,如:10.0*0.1==1.0,不可靠”。当时还不理解,10.0*0.1=1.0天经地义,咋会不可靠呢?今天知道了,电脑还是不如人脑好使。
相关资料:
大坏蛋 数据类型的BUG还是???
Kathleen Dollard 正确运用数据类型