[学习笔记]数值运算的陷阱,为什么与计算机按出来的不一样?

我们一般使用的数字型态不外乎就是int,float,double
但有关金钱的运算就需要更準确的decimal型态了

先来说一下为何不使用double呢?

大家可以试试下面这个例子

// 0.30000000000000004double a = 0.1 + 0.2;

float,double : 二进制浮点数
decimal : 十进制浮点数

会造成这个原因是因为电脑运算double会转成二进位去做运算
而小数在二进制很难完整表示,就像我们算1/3一样

所以我们需要使用更精确的decimal型态来做小数运算

// 0.3decimal b = 0.1m + 0.2m;

Tostring造成计算误差

虽然前面说数值运算要用decimal
但有时还是难免会使用到double型态
像是要计算複利时,会呼叫Math.Pow这个double funtion

//1.0221044505936159double rate = Math.pow(1.3,1.0/12.0);//1.02210445059362decimal drate = decimal.Parse(rate.Tostring());

这时发现tostring预设会四捨五入至小数点后14位
因为是在算複利,所以在几十年后会出现误差,虽然差值很小但也不容忽视

这时只要给Tostring下G17(double格式)参数就可以保留位数了

MSDN

根据预设,传回的值只包含 15 个位数的精确度虽然内部维护最多 17 个位数。 如果这个执行个体的值必须大于 15 位数,ToString会传回PositiveInfinitySymbol或NegativeInfinitySymbol而不是预期的数目。 如果您需要更多有效位数时,指定format"G17"格式规格,它一定会传回 17 个位数的有效位数或"R",它会传回 15 位数如果数目可以使用 17 位数来表示,如果只能是数字表示使用最大有效位数。

//1.0221044505936159decimal drate = decimal.Parse(rate.Tostring("G17"));

这种小数点后10几位的误差真的很难发现
http://img2.58codes.com/2024/emoticon13.gif
但牵扯到金融相关程式
还是必须排除可能的误差


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章