ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: chenzyyysl

[求助] VBA舍入遇到的一个奇怪问题

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2012-5-10 14:47 | 显示全部楼层
本帖已被收录到知识树中,索引项:自定义函数开发
本帖最后由 灰袍法师 于 2012-5-11 14:24 编辑

强烈反对28楼的代码,本来是单纯的数值运算,28楼的代码无谓地引入字符串操作,类型转换,即使能够算出正确的结果也不可取。

可以参考一下微软支持中心的自定义函数,里面就有 banker's rounding 的代码(即round to even 舍入到最接近的双数)
没有测试过,不过如果VBA的round函数出现错误的原因不查明白,那么所有VBA代码的正确性都很难保证吖。。。。。。
http://support.microsoft.com/kb/196652

btw:该网页的VBA代码还是错的!!!

此VBA代码不正确,作者自行删除。

唉,还是自己动手丰衣足食,网上下载不靠谱吖。

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-5-10 16:48 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 chenzyyysl 于 2012-5-10 16:53 编辑
灰袍法师 发表于 2012-5-10 14:47
强烈反对28楼的代码,本来是单纯的数值运算,28楼的代码无谓地引入字符串操作,类型转换,即使能够算出正确 ...


这个代码书写规范,值得学习。

不过用刚才的方法测试下,还是有一些错误。应当是不适用于我所需要的情况。
Sub xxx()
   With Sheets(1)
      For i = 1 To 100
      .Cells(i, 1) = (8 + i / 100) / 2
      .Cells(i, 2) = Round((8 + i / 100) / 2, 2)
      .Cells(i, 3) = CRound((8 + i / 100) / 2, 2)
      .Cells(i, 4) = round55((8 + i / 100) / 2, 2)
      .Cells(i, 5) = BRound((8 + i / 100) / 2, 2)
      Next i
   End With
End Sub
无标题.png

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2012-5-11 10:51 | 显示全部楼层
灰袍法师 发表于 2012-5-10 14:47
强烈反对28楼的代码,本来是单纯的数值运算,28楼的代码无谓地引入字符串操作,类型转换,即使能够算出正确 ...

请看10楼点评
http://club.excelhome.net/forum.php?mod=viewthread&tid=703244

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2012-5-11 13:33 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 灰袍法师 于 2012-5-11 14:27 编辑
一指禅 发表于 2012-5-11 10:51
请看10楼点评
http://club.excelhome.net/forum.php?mod=viewthread&tid=703244

他有他的理由,我有我的理由,没冲突吖?
VBA的类型转换本身就内含了四舍五入,用字符串算得再准,可能一个 clng,cdbl 就前功尽弃了,还无法控制,那么有何必要用字符串来计算呢?

闲着无聊写了一个跟 楼主结果一致的自定义函数
思路是完全一样的,唯一不同是,我非常害怕浮点误差,干脆全用long类型来转换。
缺点应该是可处理的数值范围会变小。
另外也不知道 mod 函数是否可靠。。。。。。

Function BRound(ByVal X As Double, ByVal Factor As Long) As Double
Dim r2 As Double, i1 As Long, i2 As Long
    i1 = Fix(X * 10 ^ Factor)
    r2 = X * 10 ^ Factor - i1
    i2 = Abs(Round(r2 * 10, 0))
    If i2 > 5 Then
        i1 = i1 + 1 * Sgn(X)
    ElseIf i2 = 5 Then
        If Abs(i1) Mod 2 = 1 Then i1 = i1 + 1 * Sgn(X)
    End If
    BRound = i1 / 10 ^ Factor
End Function

附件如下:包括了上面所有提到过的自定义函数了。
各种四舍五入自定义函数.rar (12.12 KB, 下载次数: 12)

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-5-13 10:21 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 chenzyyysl 于 2012-5-13 10:36 编辑

谢谢禅师法师的热心,这个问题的根源应当是在IEEE 754 规范,微软都没搞好,那网友们所做的能在一定条件下解决问题就不错了。
禅师推荐的方法在录入的数字(也就是小数位数有限)时,用文本处理应当可以的。
而我的实际工作中是计算得来的数字,比如8.05/2,那浮点误差就无法避免,这就要和法师的思路走到一起了。

考虑到工作中的实际情况,我在ROUND55中用的参数是E-6而不是一开始写的E-10,可以理解为百万分之一的精度。
这2天把一年所做的有关部分都改一遍,累死了。
另外,函数写得比较随手,没有定义类型,对NUM2如果不是整数要先取整,NUM1如是引用的单元格也是引用的对象,对结果没影响,但在量大时可能会影响效率。

TA的精华主题

TA的得分主题

发表于 2012-10-2 13:14 | 显示全部楼层
本帖最后由 baomaboy 于 2012-10-2 13:18 编辑
三流高手 发表于 2012-10-2 08:14
用工作表的round函数改造,那会让微软的人笑话的(我以前就是这么干了)。
因为VBA的round其实没有错,错 ...


你以前用工作表的round函数改造被微软的人笑话了?我怎么没那么荣幸被微软的人笑话一次!
我工作中全是需要四舍六入五留双的,不过我正好是使用了“让微软的人笑话的工作表round函数”改造的
用了n年了效果很好,至少在我的工作范围内处理数据还未遇到过1例错误,其他同行也都是反馈的正确信息,同样没出错误值,所以即便有“不被微软的人笑话”的方法也不去探讨了,因为我的roundy已经完全满足我的工作需要了。

Auxiliary_模块.rar

129.64 KB, 下载次数: 8

四舍六入独立版1.60.rar

92.21 KB, 下载次数: 7

TA的精华主题

TA的得分主题

发表于 2012-10-2 13:27 | 显示全部楼层
baomaboy 发表于 2012-10-2 13:14
你以前用工作表的round函数改造被微软的人笑话了?我怎么没那么荣幸被微软的人笑话一次!
我工作中全是 ...

楼主您的roundy代码能不能公布出来,让大家也学习一下啊。

TA的精华主题

TA的得分主题

发表于 2012-10-2 08:14 | 显示全部楼层
baomaboy 发表于 2012-10-1 22:39
就我所知,使用vba的round还不如使用工作表函数的round改造。

用工作表的round函数改造,那会让微软的人笑话的(我以前就是这么干了)。
因为VBA的round其实没有错,错就错在数字在计算机内部的存储上,与实际的数字可能有微小的差异上。楼主一定知道,不是所有的实数都能用二进制来表示吧。另外从逻辑上来说,微软既然在VBA中给出了采用四舍六入的round函数,又怎会让它无法使用呢?当然会有方法解决上面所说的问题啦。
楼主您在日常工作也会用到四舍六入五留双吧?很高兴能和您探讨这方面的问题。

TA的精华主题

TA的得分主题

发表于 2012-10-2 00:18 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 引子玄 于 2012-10-2 00:22 编辑

4舍5入,适用的条件是小数点后面的数字,如果连后面N位的数字都可以进位,那么,内存数字岂不是乱套了?思维逻辑的问题,死胡同钻牛角尖。

比如:3.4444
进位的结果是3
你呢?钻的牛角尖是:3.445——3.45——3.5——4
3和4的结果,能不乱套吗?


TA的精华主题

TA的得分主题

发表于 2012-10-1 15:30 | 显示全部楼层
baomaboy 发表于 2012-5-8 15:20
事实上你用VBA中的Round当4舍6入5成双用会出现很多的错误值,不只是4.03,
Round(1.225, 2)
Round(1.245, ...

据您所知,有没有解决的方法呢?
我有一个方法,如有兴趣,可以和您探讨一下。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2025-1-5 07:52 , Processed in 0.029808 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表