VBA: 小数存储精度问题single vs. double

在写程序的时候发现了这样一个问题,我在一个单元格保存了一个小数30.13,偶然的情况下发现,这个小数乘以1以后得到的竟然不是30.13而是30.1299991607666。

联想到我设置的数据类型是single(非科班出身,对数据类型和构成没有神马研究),索性单独写了一小段,看是不是数据结构的问题:

Sub check()
    Dim sin As Single
    Dim dou As Double
    Dim var As Variant

    sin = Cells(1,1).Value
    dou = Cells(1,1).Value
    var = Cells(1,1).Value

    Cells(3,1).Value = sin
    Cells(4,1).Value = dou
    Cells(5,1).Value = var

End Sub
将30.13放在单元格A1内,运行check(),在A3,A4,A5内得到的结果分别是

30.1299991607666

30.13

30.13

说明在2位小数点得情况下,Double是可以保证数据的准确度的。而Variant也可以准确的找到Double形式用于存储。


然后稍微查了一下Single和Double的相关信息,有一个解释很明白:

计算机只能处理 2进制数。然而,只有少数小数能够被完整表达成二进制数(比如:十进制的0.125=二进制的(0.001),或者说 1*2^(-3),而十进制的 0.1 表示成二进制的话就成了无限小数一般:1*2^(-4)+1*2^(-5)+1*2^(-8)+1*2^(-9)+……)。而计算机的内存位数肯定是有限的,所有总会有取舍!
这是硬件上的局限性引起的,不是软件的错误!
我们再从另外一个角度来看问题,即数据的有效性问题!或许楼主可能会知道任何数据的测量是不可能精确和准确的!所以,任何数据所测的结果只有统计学上的意义,它在一定范围内才是准确的!同时,受制于测量仪器或仪表的精度,它的有效性范围也是不同的。最直接的表现就是它的有效位数是不同的。比如说,你用一个直尺来量一个东西的长度,得到的值是 2.5 mm(最后一位是你自己估计的,因为直尺上没有 0.1 mm 的刻度)。这时你又换用一个游标卡尺来测量这个东西,得到的结果是:2.385 mm (游标卡尺的最小刻度是 0.02 mm。最后一位 5也是估计出来的)。相信大家一看就明白,前者的 2mm肯定是准确的,0.5mm是不准确的;而后者的2.38mm 肯定是准确的,但 0.005mm 是不准确的。所以,在数据处理过程中会特别强调数据的有效位数,即它的精度!

严格意义上讲,即使是Double也无法完全保证数据的精确程度,只是相对而言要比Single准确很多。所以大多数情况下,解决小数存储不精确的方法有两种:

一来直接用Variant或者Double作为数据类型来进行读取和存储

二来,如果用Single,那么尽量在VBA中添加Round函数来限制小数位数,避免出现进一步的问题。

===============================================

参考链接:

VBA:如何定义两位小数的变量

单精度和双精度?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值