【问题标题】:VBA Val Function Changing Value?VBA Val函数改变值?
【发布时间】:2017-06-08 08:51:06
【问题描述】:

一个方程产生这个值作为变量/双 X:36.0418746812314

但是:
X Val(X) 为真
X CStr(X) 为假
X CDdl(X) 为假

Val() 如何改变值?
在观察列表中查看时,应用 X = Val(X) 似乎不会改变 X 的值或类型。但不知何故它是不同的。

例如:
A = X - Val(X) 非常小,但不为零 (2.1316282072803E-14)。
B = X - CStr(X) 非常小,但不为零 (2.1316282072803E-14)。
C = X - CDbl(X) 为零。

更新: 感谢大家的回复和回答。这里有一些额外的背景。

股息调整收盘价的公式。据报道被雅虎财经使用。
A1 = A0 + A0 * (((P1 / S) - P0 - D) / P0)

分割和股息调整收盘价
股票代码:INTC
日期:1980 年 8 月 29 日,星期五
0.306757021582758(雅虎财经计算)
0.306757021582704(我的 VBA 计算)

将 A1 转换为字符串 CStr(A1) 或应用 Val(A1),然后我的 VBA 结果与 Yahoo Finance 计算值匹配。
这并不是真正的实质性差异,但很高兴了解为什么以及如何使其匹配以进行公式验证。

公式来源、组件细节和解释。
“雅虎如何计算调整后的收盘价”
http://marubozu.blogspot.com/2006/09/how-yahoo-calculates-adjusted-closing.html

【问题讨论】:

  • 您确定这是X 的确切值吗?我刚刚测试并获得了所有测试的False。 (FWIW - X <> CStr(X) 隐式等于 CStr(X) <> CStr(X) 因为 VBA 需要在执行比较之前执行类型转换。)

标签: vba


【解决方案1】:

考虑一下这个 MCVE:

Sub TestingVal()
  Dim x As Double, y As Double
  x = 36.0418746812314 + 2.1316282072803E-14
  y = Val(x)
  Debug.Print x, y, x <> y       ' 36.0418746812314  36.0418746812314  True
End Sub

由于显示精度,x 和 Y显示的方式相同。但是它们的实际值(二进制表示)是不同的。

有关信息,以下是IEEE-754 格式的 x 和 y 的二进制表示:

0100000001000000000001010101110000100110010010010011010110101110
0100000001000000000001010101110000100110010010010011010110101011
'                                                            ^^^

只有最后 3 位(尾数)不同!当它们以 10 为底和 14 位十进制数字显示时,这种差异不足以显示出来。

现在考虑Val Function

将字符串中包含的数字作为适当类型的数值返回

这意味着,在Val(x) 中,数字x 首先被转换为String 以匹配函数的参数类型。这导致它的 显示值 以 10 为基数。然后Val 将其转换回一个数字,我们将其存储在y 中。由于在第一阶段显示的值不是 exact 值,因此丢失了一些精度,我们得到了x &lt;&gt; Val(x)

作为结论,当精度对计算的最后一位很重要时,不要在数字上应用Val。即使您不知道您的初始变体是双精度型还是字符串型,请使用CDbl,这两种情况都适用。

【讨论】:

  • 看起来已经大量努力研究这个答案 - 干得好!
  • @YowE3K 谢谢老兄。更重要的是,我今天学到了一些“巨大”的东西。我们从不停止学习,即使我们开始掉头发......
  • 我的脑细胞确实在流失,但我的头发还没有开始掉(这让我的理发师很反感 - 一直抱怨我的头发太厚,需要额外收费来磨头发)剪刀:()
  • 当然,另一件需要警惕的事情是尝试在 any 类型的相等/不等比较中使用 Double - 例如49 * CDbl(1 / 49) = 1False 由于最后一位的舍入。 (如果只是 49 * (1 / 49) = 1 你会得到 True - 不确定这是由于优化,还是它是否在中间计算中存储了额外的位)
  • 为什么不直接使用CDec 而不是CDbl,并保留打印精度? Debug.Print CDec(36.0418746812314) + CDec(2.1316282072803E-14) 'Prints 36.041874681231421316282072803
【解决方案2】:

CDbl 功能与您的区域设置相关。 Val 函数与美国区域设置相关。

如果您在本地区域设置中向 Val 函数提供值,它将被解释为美国格式(小数分隔符为句点,千位分隔符为逗号等)。

我的电脑设置为 EN-AU 设置(类似于 EN-US 设置),Val(36.0418746812314) = 36.0418746812314 返回 True,或者在您的语法中,Val(36.0418746812314) &lt;&gt; 36.0418746812314 返回 False

【讨论】:

  • 嗨。问题实际上是 x 的实际值是 36.0418746812314 + 2.1316282072803E-14 但它显示为 36.0418746812314... 并且 Val(x) 将其截断回显示的内容。 (即使是美国语言环境):(。我想弄清楚如何更精确地显示x
  • @A.S.H 使用CDec
猜你喜欢
  • 2015-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多