VBAdebugging器精度

我有一个single ,我相信C + +等价物是在Excel工作簿模块中的VBA float 。 无论如何,我最初分配的值(876.34497)在即时窗口中四舍五入为876.345,并且在VBA上设置断点时监视并hover工具提示。 但是,如果我将这个Single传递给C ++ DLL,C ++会将其报告为原始值876.34497。

那么,它实际上是作为原始值存储在内存中吗? 这是debugging器的一些限制吗? 不确定这里发生了什么。 难以testing我所传递的是我在C ++端得到的东西。

在这里输入图像说明

我试过了:

 ?CStr(test) 876.345 ?CDbl(test) 876.344970703125 ?CSng(test) 876.345 

VBA不是非常简单,所以在某些层面上,它必须以876.34497的forms存储在内存中。 否则,我不认为CDbl会是正确的。

“single”types的VBAvariables存储为“IEEE 754 [ – ] 1985 [原文如此]的32位硬件实现”。 [见: https : //msdn.microsoft.com/en-us/library/ee177324.aspx] 。

这意味着英文的意思是,“单”精度数字被转换为二进制,然后截断,以适应4字节(32位)序列。 确切的过程在维基百科中很好地描述在http://en.wikipedia.org/wiki/Single-precision_floating-point_format 。 结果是所有的单精度数字表示为

 (1) a 23 bit "fraction" between 0 and 1, *times* (2) an 8-bit exponent which represents a multiplier between 2^(-127) and 2^128, *times* (3) one more bit for positive or negative. 

将数字转换为二进制和后面的过程会导致两种舍入错误:

(1)重要数字 – 你已经注意到,有效数字是有限制的。 22位整数只能有8,388,607个唯一值。 换句话说,不能以大于+/- 0.000012%的精度表示数字。 回到高中科学,你可能会记得,这是另一种说法,你不能指望超过六位有效数字(呃,十进制数字,至less…当然你有22个重要的二进制数字)。 所以任何一个有六位以上有效数字的数字都会被四舍五入。 但是,它不会四舍五入到最接近的十进制数字……它会四舍五入到最接近的二进制数字。 这往往会导致一些意想不到的结果(如你的)。

(2)二进制转换 – 另一种types的错误更为有害。 有一些数字显着less于六位(十进制)的数字,会四舍五入。 例如,十进制的1/5是0.2000000。 它永远不会“四舍五入”。 但在二进制相同的数字是0.00110011001100110011 ….重复永远。 (该顺序相当于1/8 + 1/16 + 1/16 *(1/8 + 1/16)+ 1/256 *(1/8 + 1/16)…)二进制数字代表0.20,然后转换回十进制,你永远不会得到完全0.20。 例如,如果您使用了八位,那么二进制中的0.00110011就是:

  0.12500000 0.06250000 0.00781250 + 0.00390625 ------------ 0.19921875 

不pipe你使用多less个二进制数字,你永远不会得到0.20,因为0.20不能表示为两个幂的和。

这简而言之就是解释发生了什么事情。 当您将876.34497分配给“testing”时,它将在内部转换为:

 1 10001000 0110110001011000010011 136 5,969,427 

(+1)* 2 ^(136-127)*(5,969,427)/(2 ^ 23)

Excel会自动截断单精度数字的显示,只显示六位有效数字,因为它知道第七位数字可能是错误的。 我不能告诉你这个数字是什么,因为我的Excel没有显示足够的有效数字! 但是你明白了。

将值强制为双精度时,它使用整个二进制string,然后在结尾处添加另外4个字节的零值。 它现在允许显示两倍的有效数字,因为它是双精度的,但正如你所看到的,从8个十进制数字到23个二进制数字的转换,然后追加另一个长的零串,引入了一些错误。 不是真的错误,如果你明白它在做什么; 只是文物。 毕竟,它正在做你刚才告诉它做的事……你只是不知道你在告诉它做什么!