为什么CLng产生不同的结果?

时间:2011-02-14 08:03:11

标签: vba casting rounding floating-accuracy

这是我的VBE(MS Excel 2007 VBA)中的一个小宝石:

?clng(150*0.85)
 127 
x = 150*0.85
?clng(x)
 128 

有人可以解释这种行为吗?恕我直言,第一个表达式应该产生128(.5舍入到最接近的偶数),或者至少两个结果都应该相等。

5 个答案:

答案 0 :(得分:11)

我认为wqw是对的,但我会详细说明。

clng(150 * 0.85)语句中,150 * 0.85以扩展精度计算:

150 = 1.001011 x 2^7
双精度=

中的

0.85

1.1011001100110011001100110011001100110011001100110011 x 2^-1

手动乘以这些

1.1111110111111111111111111111111111111111111111111111110001 x 2^6 =
127.4999999999999966693309261245303787291049957275390625

这是59位,非常适合扩展精度。它比127.5小得多。

在语句x = 150 * 0.85中,该59位值四舍五入为53位,给出

1.1111111 x 2^6 = 1111111.1 = 127.5

所以它按照半个对偶的方式进行整理。

(有关详细信息,请参阅我的文章http://www.exploringbinary.com/when-doubles-dont-behave-like-doubles/。)

答案 1 :(得分:2)

关于VBA的一个“有趣”的事情是对CInt()等的四舍五入是所谓的银行家四舍五入。银行家舍入是0.5值向上或向下取整的位置,具体取决于数字是偶数,所以2.5轮到2,3.5到4等等。

这里可以找到关于舍入的更多内容

http://www.consultdmw.com/rounding-numbers.htm

答案 2 :(得分:1)

这是一个猜测,但.85可能无法表示为浮点数。如果它被0.0000000000001关闭,它仍然会以奇怪的方式影响舍入。

如果您使用CDec(.85)强制它进入十进制模式,您就不会觉得奇怪。这是我不使用单/双的众多原因之一,其中准确性很重要。

答案 3 :(得分:1)

我的理论是VBA / VB6使用x87进行浮点计算,如果中间结果为80位,则隐式地将双精度转换为更高的精度。因此,对v的赋值或使用CDbl的显式转换将中间80位值转换回64位有效地舍入(或截断它)。

以下是一些讨论:

Extended (80-bit) double floating point in x87, not SSE2 - we don't miss it?

答案 4 :(得分:0)

Kevin和Jonathan所说的都是真的,但Jonathan的回答更适用于此。如果您处理货币类型数字而不是浮点数,那么将应用银行家的舍入规则。