【问题标题】:Why does CLng produce different results?为什么 CLng 会产生不同的结果?
【发布时间】:2011-02-14 08:03:10
【问题描述】:

这是直接来自我的 VBE(MS Excel 2007 VBA)的小宝石:

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

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

【问题讨论】:

  • 很奇怪。 CLng(CDbl(150*0.85)) 修复它。 Round(150*0.85) 也是。
  • CSng 也是如此。我的理论是这是一个浮点错误。

标签: vba casting rounding floating-accuracy


【解决方案1】:

我认为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/。)

【讨论】:

    【解决方案2】:

    啊,关于 VBA 的“有趣”之一是 CInt() 等的舍入,这就是所谓的银行家舍入。银行四舍五入是根据数字是否为偶数将 0.5 值向上或向下舍入,因此 2.5 舍入为 2、3.5 舍入为 4,依此类推。

    更多关于四舍五入的信息可以在这里找到

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

    【讨论】:

    • 他提到即使在问题中也应该四舍五入到最接近的值。
    • 在这种情况下,127 不是“最近的偶数”。这说明不了什么。
    【解决方案3】:

    这有点猜测,但 .85 可能无法表示为浮点数。如果它偏离 0.0000000000001,它仍然会以奇怪的方式影响舍入。

    如果您使用 CDec(.85) 将其强制为十进制模式,您就不会感到奇怪。这是我在精度很重要时不使用单/双的众多原因之一。

    【讨论】:

    • 第一个结果可能来自舍入误差(.4999... 而不是 .5),但在这种情况下,第二个结果也应该是 127。据我了解,对 x 的中间分配不应该影响演员表的结果。
    【解决方案4】:

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

    这里有一些讨论:

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

    【讨论】:

      【解决方案5】:

      凯文和乔纳森所说的都是真的,但乔纳森的回答在这里更适用。如果您处理的是货币类型的数字而不是浮点数,则将应用银行家的四舍五入规则。

      【讨论】:

      • CLng 应用银行家四舍五入
      • 是的,但是如果它应用舍入的对象已经是一个二进制浮点数,其中包含相对于十进制表示的舍入错误,这并不重要。该数字已经略高于或低于 1/2 路点,因此将永远不会应用舍入算法用于解析 1/2 路值的任何规则。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-10
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多