标题:VB代码执行效率问题:abs(负数) 与 0-负数,那条语句执行更快?
只看楼主
wufuzhang
Rank: 9Rank: 9Rank: 9
来 自:广州
等 级:贵宾
威 望:21
帖 子:206
专家分:1346
注 册:2017-8-9
结帖率:100%
已结贴  问题点数:5 回复次数:13 
VB代码执行效率问题:abs(负数) 与 0-负数,那条语句执行更快?
代码一:
Dim lngX As Long
Dim lngY As Long
If lngX<0 then
   lngY=Abs(lngX)
Else
   lngY=lngX
End if

代码二:
Dim lngX As Long
Dim lngY As Long
lngY=lngX
If lngX<0 then   lngY=0-lngX

这两段代码,哪条执行比较快?还是差不多?

搜索更多相关主题的帖子: 代码 执行 abs 负数 Dim 
2018-05-03 14:18
wufuzhang
Rank: 9Rank: 9Rank: 9
来 自:广州
等 级:贵宾
威 望:21
帖 子:206
专家分:1346
注 册:2017-8-9
得分:0 
==================
主要是不知道VB里面Abs()函数是怎么实现的,
0-负数是怎么实现的,求哪位大神指点一下。

不经历千百遍的调试,怎能体会成功时那一刹那的喜悦。
2018-05-03 15:04
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
得分:0 
测试后结果是:IDE环境下运行abs效率高,编译后执行if判断的效率高。
测试代码如下:
Private Sub Command1_Click()
  Dim t As Double, a As Long, b As Long, i As Long
  a = -1234
  t = Timer
  For i = 0 To 100000000
    b = a
    If a < 0 Then b = -a
  Next
  MsgBox Timer - t
End Sub

Private Sub Command2_Click()
  Dim t As Double, a As Long, b As Long, i As Long
  a = -1234
  t = Timer
  For i = 0 To 100000000
    b = Abs(a)
  Next
  MsgBox Timer - t
End Sub


能编个毛线衣吗?
2018-05-03 15:08
wds1
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:贵宾
威 望:49
帖 子:393
专家分:2025
注 册:2016-3-10
得分:0 
当然是0-lngX快。
不论怎么实现,abs都需要额外调用内部函数。
2018-05-03 15:31
wufuzhang
Rank: 9Rank: 9Rank: 9
来 自:广州
等 级:贵宾
威 望:21
帖 子:206
专家分:1346
注 册:2017-8-9
得分:0 
我把代码补全了测试结果是:IDE环境下运行Abs函数效率更高(1.4S左右,另一种方法1.7S左右),
编译后Abs函数效率更低了(0.35S左右,另一种方法0.15S左右)
@wmf2014回答得没错
现在问题来了,为什么IDE环境和编译后,两段代码执行的效率居然相反呢?
测试代码:
Private Sub Command1_Click()
  Dim t As Double, a As Long, b As Long, i As Long
  a = -1234
  t = Timer
  For i = 0 To 100000000
    b = a
    If a < 0 Then b = 0 - a
  Next
  MsgBox Timer - t
End Sub

Private Sub Command2_Click()
  Dim t As Double, a As Long, b As Long, i As Long
  a = -1234
  t = Timer
  For i = 0 To 100000000
    If a < 0 Then
       b = Abs(a)
    Else
       b = a
    End If
  Next
  MsgBox Timer - t
End Sub

不经历千百遍的调试,怎能体会成功时那一刹那的喜悦。
2018-05-03 15:35
wufuzhang
Rank: 9Rank: 9Rank: 9
来 自:广州
等 级:贵宾
威 望:21
帖 子:206
专家分:1346
注 册:2017-8-9
得分:0 
回复 4楼 wds1
可以亲测,IDE环境和编译后,两段代码执行效率相反。

不经历千百遍的调试,怎能体会成功时那一刹那的喜悦。
2018-05-03 15:38
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4912
专家分:29900
注 册:2008-10-15
得分:5 
测试代码:
程序代码:
Private Sub Command1_Click()
  Dim t As Double, a As Long, b As Long, i As Long
  Dim s As String
  
  a = -1234
  t = Timer
  For i = 0 To 100000000
    b = a
    If a < 0 Then b = 0 - a
  Next
  s = "方法一耗时:" & (Timer - t)
  
  a = -1234
  t = Timer
  For i = 0 To 100000000
    If a < 0 Then
       b = Abs(a)
    Else
       b = a
    End If
  Next
  s = s & vbCrLf & "方法二耗时:" & (Timer - t)
  
  a = -1234
  t = Timer
  For i = 0 To 100000000
    If a < 0 Then
        b = -a
    Else
        b = a
    End If
  Next
  s = s & vbCrLf & "方法三耗时:" & (Timer - t)
  
  Text1.Text = s
End Sub


IDE环境运行结果:
方法一耗时:1.66900000000157
方法二耗时:1.29599999999988
方法三耗时:1.26999999999779


编译为本机代码运行结果:
方法一耗时:.116000000001165
方法二耗时:.212000000002796
方法三耗时:.0450000000032595


编译为伪代码运行结果:
方法一耗时:1.22499999999837
方法二耗时:1.04100000000326
方法三耗时:1.23399999999855


从我测试的结果来看,认真优化后的代码,不管IDE还是编译成本机代码
if 都比 abs 要快。

你方法一中:分析均忽略需要生成的寻址
    b = a                      产生 内存复制代码
    If a < 0 Then b = 0 - a    产生条件跳转和一条内存复制代码

我优化后,方法三中:
    If a < 0 Then          产生条件跳转
        b = -a             一条内存复制,和一条无条件转移命令
    Else
        b = a              第二条内存复制命令,但这二条内存复制命令只会执行一条,
    End If

无条件转移命令,好像是只需二个时钟周期,内存复制,二个寻码,一个复制,我不知道了。
等于减掉了一次内存复制,增加了一次无条件转移,节省了不少的时钟周期。

授人于鱼,不如授人于渔
早已停用QQ了
2018-05-03 16:54
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4912
专家分:29900
注 册:2008-10-15
得分:0 
为啥 IDE 环境与 编译后 时间有这么大的差距,
我认为原因在于 VB6 的IDE环境,还是 解释执行 造成的。
编译伪代码是 解释执行的。

去掉所有检查编译成本机代码运行结果
方法一耗时:5.00000000029672E-02
方法二耗时:3.10000000000592E-02
方法三耗时:3.09999999973805E-02


说明VB生成的代码,会加入很多检测代码在内,每多一步运算,都要经过一批检查。

授人于鱼,不如授人于渔
早已停用QQ了
2018-05-03 16:59
wds1
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:贵宾
威 望:49
帖 子:393
专家分:2025
注 册:2016-3-10
得分:0 
方法1的循环内多了 b = a过程,两者比较是不准的。

相同过程情况,方法1速度快。

在开发环境,两者效率应该差不多,因为都需要解释执行,所以速度几乎一致。

在编译环境,方法1虽然增加了赋值过程,但是由于没有调用abs,总体时差就显示出来了。  

2018-05-03 17:23
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4912
专家分:29900
注 册:2008-10-15
得分:0 
CPU Disasm
地址        十六进制数据            汇编代码                                                    注释
00401C1E   .  B9 00E1F505   mov ecx,5F5E100                                         ; 循环终止值
00401C23   .  BA 01000000   mov edx,1                                               ; 1
00401C28   .  33C0          xor eax,eax                                             ; 循环变量起始清零
00401C2A   >  3BC1          cmp eax,ecx                                             ; 比较循环变量与终止值,循环体开始
00401C2C   .  7F 1C         jg short 00401C4A                                       ; 是否跳出循环
00401C2E   .  3BFE          cmp edi,esi                                             ; 是否小于零
00401C30   .  7D 0A         jge short 00401C3C                                      ; 小于零跳
00401C32   .  8BDF          mov ebx,edi                                             ; EDT到EBX
00401C34   .  F7DB          neg ebx                                                 ; 求补指令,相当于0-这个数
00401C36   .  0F80 33020000 jo 00401E6F                                             ; 是否溢出
00401C3C   >  8BDA          mov ebx,edx
00401C3E   .  03D8          add ebx,eax                                             ; 计算循环变量
00401C40   .  0F80 29020000 jo 00401E6F                                             ; 是否溢出
00401C46   .  8BC3          mov eax,ebx                                             ; 保存循环变量
00401C48   .^ EB E0         jmp short 00401C2A


CPU Disasm
地址        十六进制数据            汇编代码                                                    注释
00401CAD   > /8B4D E8       mov ecx,dword ptr [ebp-18]                              ; 循环计数读到 ecx中
00401CB0   . |B8 00E1F505   mov eax,5F5E100                                         ; 循环终值读到 eax中
00401CB5   . |3BC8          cmp ecx,eax                                             ; 比较是否到达循环次数
00401CB7   . |7F 22         jg short 00401CDB                                       ; 达到循环次数跳循环外
00401CB9   . |8B4D E4       mov ecx,dword ptr [ebp-1C]                              ; b = a
00401CBC   . |85C9          test ecx,ecx                                            ; 测试
00401CBE   . |7D 06         jge short 00401CC6                                      ; 符号为零,则跳转
00401CC0   . |FF15 1C104000 call dword ptr [<&MSVBVM60.__vbaI4Abs>]                 ; 调用 abs 函数,没跟入
00401CC6   > |8B4D E8       mov ecx,dword ptr [ebp-18]                              ; 循环计数读到ECX中
00401CC9   . |B8 01000000   mov eax,1                                               ; 把1放到EAX中
00401CCE   . |03C1          add eax,ecx                                             ; EAX+ECX
00401CD0   . |0F80 99010000 jo 00401E6F                                             ; 加法是否溢出,溢出跳出错
00401CD6   . |8945 E8       mov dword ptr [ebp-18],eax                              ; 循环结果放内存
00401CD9   .^\EB D2         jmp short 00401CAD                                      ; 返回去循环


CPU Disasm
地址        十六进制数据            汇编代码                                                    注释
00401D49   .  B9 00E1F505   mov ecx,5F5E100                                         ; 循环终值
00401D4E   .  33C0          xor eax,eax                                             ; 清零eax
00401D50   >  3BC1          cmp eax,ecx                                             ; 比较循环变量,ECX中终止值
00401D52   .  7F 11         jg short 00401D65                                       ; 跳出循环
00401D54   .  BA 01000000   mov edx,1                                               ; edx 放1
00401D59   .  03D0          add edx,eax                                             ; 循环变量+1
00401D5B   .  0F80 0E010000 jo 00401E6F                                             ; 是否溢出
00401D61   .  8BC2          mov eax,edx                                             ; 保存循环变量
00401D63   .^ EB EB         jmp short 00401D50                                      ; 继续循环,天哪,赋值命令去哪了



授人于鱼,不如授人于渔
早已停用QQ了
2018-05-03 17:56



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-486584-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017266 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved