【问题标题】:For Loop SKIPPING Last Iteration in VB (baffled) Code Included, Tested, Still Not Working [closed]For Loop SKIPPING Last Iteration in VB (baffled) Code Included, Tested, still not working [关闭]
【发布时间】:2012-07-06 21:17:48
【问题描述】:

这是一个简单的例子:

Dim si As Single
For si = 2.6 To 3.3 Step 0.1
  MsgBox si
Next si

我得到的数字如下(在MsgBox中显示如下):

2.6
2.7
2.8
2.9
3
3.099999
3.199999
3.299999

所以,我想我应该将数据类型从 Single 更改为 Double,看看会发生什么。这一次,没有 .099999 类型编号,但最后一项(迭代)被跳过,如中,缺失,不存在。以下是 MsgBox 显示中显示的结果):

2.6
2.7
2.8
2.9
3
3.1
3.2

我猜在缺少最后一次迭代的情况下,它会像 .299999 一样跟踪它,并且在自己的脑海中永远不会达到 .3,所以跳过它?但是,这样做的问题是,如果发生这种情况,您会得到一个先前的迭代出现两次才能发生这种情况,就像在单一数据类型示例中所做的那样,如果您在第一个小数,你会注意到 3.0 出现了两次。首先是“3”,然后是“3.0”(如果我们忽略/截断“3.0”部分之后出现的 5 次数字 9 - “3.099999”)。

有趣的是,我使用单数据类型循环遍历某些内容的另一个函数显示了我们上面的双数据类型示例所存在的确切问题,而我们上面的单数据类型示例没有任何问题。所以,我在这里的真正原因是我的 Single Data Type 循环丢失并在使用“Step 0.1”时跳过了最后一项(递增 0.1)。

是否有可靠的方法使用“Step 0.1”和非整数数据类型来执行此操作?如果不是,我们是否知道这些混乱事物发生的规则(也就是说,混乱是可预测的)? 叹息

我以为你们都会觉得这很有趣,我当然很期待理解它。搜索谷歌是没用的,因为我一输入“for”和“step”的工作,就不断提出如何使用 step 运算符的示例,没有任何用处。

我很想知道如何忍受这种情况,或者安全地做到这一点,和/或首先为什么会发生这种情况。我宁愿不为这个特定的函数使用整数循环(然后使用另一个变量进行划分以获得我的十进制类型),但是如果我必须这样做并且没有可靠的方法可以做到这一点,我会的。但我把这个留给你们,我的程序员霸主。

我的示例发生在 VB6 中,但是,我也想知道在 VB.NET 甚至 C# 中是否也发生了同样的混乱?我假设它发生在 vba 和 vbscript 中。任何有关这方面的信息也会很有趣并受到赞赏。

提前谢谢你。

致版主(不是问题的必要阅读):这不是重复的帖子,可能有其他人用其他语言(例如 C#)发布浮点问题,但解决方案这个(VB6)问题不一定与C#问题的解决方案相同。可能有一些相同的解决方案,但也会有不同的解决方案,我无法从 C# 帖子中获得不同的解决方案/答案。事实证明,我感兴趣的解决方案是一个 VB6 特定的解决方案,在引用的 C# 帖子中找不到该解决方案。我敦促模组在尝试关闭帖子之前要勤奋,我看到帖子在很多场合被不公平地关闭,并且在一天结束时,你会进入一个没有增加任何价值的阶段,但从本网站的 Q 和 A 风格中删除了实质性价值。总之,如果一个类似的帖子甚至有可能提供新的信息/答案或解决方案,你最好不要关闭。特别是如果问题是针对不同语言的,即使概念相似或相同,也必然会有不同的解决方案和特定于语言的解决方案。

【问题讨论】:

标签: c# vb.net vba vb6 vbscript


【解决方案1】:

问题归结为浮点数在内存中的表示方式。许多其他人发布了有关了解浮点数表示方式的良好参考资料的链接。

当您尝试使用双精度而不是单精度时,数字递增如下 - 必须使用调试器逐步获取值,因为 ToString 不会输出值的完整精度。

2.6
2.7
2.8000000000000003
2.9000000000000004
3.0000000000000004
3.1000000000000005
3.2000000000000006
3.3000000000000007

如您所见,最终值略高于 for 循环的结尾,因此被跳过。

通过使用整数,您可以避免 for 循环中的浮点问题,但您需要在每次迭代中将该数字除以 10 以获得您想要打印的值。

Dim i As Integer
For i = 26 To 33 Step 1
        MsgBox(i / 10)
Next

【讨论】:

  • +1 以获得合理且正确的答案
【解决方案2】:

尝试使用小数来代替精度:

For i As Decimal = 2.6 To 3.3 Step 0.1
  MessageBox.Show(i.ToString)
Next

如果使用 VB6,您可以尝试使用 Currency 类型(如 JeffSiver 所述):

Dim i As Currency
For i = 2.6 To 3.3 Step 0.1
  MsgBox i
Next

【讨论】:

  • 我们在 vb6 中没有小数点,但我认为我可以使用变体,即使使用变体,最后一项也会丢失。这是将 0.1 添加到单/十进制/双精度数据类型的问题,还是仅当 For 循环使用非整数 Step 运算符执行此操作时才会出现问题?
  • 在 VB6 中,我会使用货币数据类型。这是十进制数据类型,小数点右侧有固定的四位数字。我确定问题是由于浮点数的性质造成的。在 VB.NET 和 c# 中,我会使用 @LarsTech 推荐的小数类型。
  • @jeff siver 但现在我担心对单个或非整数数据类型进行基本算术运算会遇到同样的问题,还是会这样?比如,在 for 循环中添加 0.1 到 2.9,但是通过使用整数循环遍历事物并将它们除以 10,我会有这个问题吗?
  • @jeff siver 哇,我只是在上面的例子中使用了货币数据类型,一切正常。没有 .099999 和没有丢失的迭代,就像我遇到的主要问题(丢失的最后一次迭代)现在已经解决了。您是否知道这是否可靠,为什么会发生,我可以期望它在客户端机器上像这样工作吗?还是这也受混沌规则的约束?
  • @Erx_VB.NexT.Coder VB6 确实有 Decimal 数据类型。它有 14 个字节的精度。您错过了所有答案和 cmets 的重点。计算机使用二进制数字系统,您的问题只是一个舍入错误。所有编程语言都有这个问题。使用精度更高的变量可以减少问题,但不能消除它。您将需要以某种方式更改您的代码,因为您的迭代不会以当前的形式工作。如果您想完全了解该问题,请转到 cmets 中给出的链接之一,或以前的答案。
【解决方案3】:

我会乘以 10 并在循环中使用整数。即使使用decimal,我认为您也可能遇到相同类型的问题

【讨论】:

  • 好的,如果我乘以 10 或使用 do 循环,将 0.1 添加到单个数据类型会产生与 .099999 相同的问题吗?这是使用非整数 Step 的 For 循环的问题,还是算术的简单问题(即:我无法可靠地将 0.1 添加到单个数据类型)...?
  • 问题是 0.1 并不是真正的 0.1,所以 for 基本上是一个最后加上和比较的循环,失败了。因此,将其减少为整数(因此,如果您的数字是 0.1、0.2 等,则乘以 10 并四舍五入,并使步长 = 1)
猜你喜欢
  • 1970-01-01
  • 2022-12-26
  • 2022-12-02
  • 2017-01-29
  • 2019-11-30
  • 2022-12-28
  • 1970-01-01
  • 2013-03-25
  • 2013-04-24
相关资源
最近更新 更多