下面是我的代码:
Dim temrecord2(360, 1) As Long
Dim i, j, k, l, f As Integer
Dim count As Integer
Dim cx, cy, csx, csy As Long
Dim jl As Single        For l = 0 To 360
            For i = 0 To 360
                  If i - l < 0 Then
                        temrecord(i, 0) = record(i - l + 360, 0)
                    Else
                        temrecord(i, 0) = record(i - l, 0)
                    End If
                    temrecord(i, 1) = 1
            Next
                        
            For f = 0 To 360
                For j = 0 To 360
                    csx = Int((basicrecord(f, 0) * Cos(f * pi180) - temrecord(j, 0) * Cos(j * pi180)))
                    csy = Int((basicrecord(f, 0) * Sin(f * pi180) - temrecord(j, 0) * Sin(j * pi180)))
                    count = 0                    For k = 0 To 360
                        cangle = (k + 90) * pi180
                        cx = (temrecord(k, 0)) * Sin(cangle) + csx
                        cy = (temrecord(k, 0)) * Cos(cangle) + csy                        jl = Sqr((cx - temrecord2(1, 0)) ^ 2 + (cy - temrecord2(1, 1)) ^ 2)
                        If jl > Val(Text7.Text) Then
                            count = count + 1
                        End If
                        If count > 180 Then Exit For
                        Next
                    DoEvents
                Next
            Next
        Next就这些运算,要完成就需要差不多20个小时,根本无法接受~
请问还能提高运算效率吗?
要如何改呢?

解决方案 »

  1.   

    f,j,k循环中没有用到l循环,可单独拿出来!这就少了一层循环嘛!
      

  2.   

    不懂。但还是给点建议:
    1--Dim temrecord2(360, 1) As Long 
       二维数组的第二维就只有0,1个值,不知能否用两个一维数组来代替?2--Dim i, j, k, l, f As Integer 
      改为Dim i As Integer , j As Integer , k As Integer , l As Integer , f As Integer3--Dim cx, cy, csx, csy As Long 类似2
    4--给每个Next后面添上对应的 i、j、k等计数因子。
      

  3.   

    csx = Int((basicrecord(f, 0) * Cos(f * pi180) - temrecord(j, 0) * Cos(j * 
    csy = Int((basicrecord(f, 0) * Sin(f * pi180) - temrecord(j, 0) * Sin(j * 
    这两句里面的
    (basicrecord(f, 0) * Cos(f * pi180)和
    (basicrecord(f, 0) * Sin(f * pi180)
    属于重复计算,完全可以把这部分放到j循环外面temrecord(k, 0))也一样
      

  4.   

    改程序的功能是通过比较两个图形,判断第二个图形的旋转角度,和位移
    这两个图形比较简单,可以看多是两个圆,一个圆有360个点组成,通过改变第二个圆的角度,和位置,不断与第一个圆比较,从而判断出,第二个圆相对与第一个圆旋转了的角度有多少,位移有多少~~现在我把吻合度小于50%的就跳出对比的循环,提高了一倍效率。当第二个圆的圆心移出第一圆时不进行判断,效率又提高了近一倍。
    不过现在还要5-6小时,才能完成啊~~~还有没有好办法啊???
             For l = 0 To 360
                For i = 0 To 360
                      If i - l < 0 Then
                            temrecord(i, 0) = record(i - l + 360, 0)
                        Else
                            temrecord(i, 0) = record(i - l, 0)
                        End If
                        temrecord(i, 1) = 1
                Next
                            
                For f = 0 To 360
                    bcy = basicrecord(f, 0) * Sin(f * pi180)
                    bcx = basicrecord(f, 0) * Cos(f * pi180)
                    For j = 0 To 360
                        contimerc = contimerc + 1
                        csx = Int((bcx - temrecord(j, 0) * Cos(j * pi180)))
                        csy = Int((bcy - temrecord(j, 0) * Sin(j * pi180)))
                        count = 0                    If csx <> 0 Then '获取圆心移动的角度
                            If csy >= 0 And csx >= 0 Then
                                tangle = Int(Atn(csy / csx) / 3.1415926 * 180)
                            Else
                                If csx < 0 Then
                                    tangle = Int((Atn(csy / csx) + 3.1415926) / 3.1415926 * 180)
                                Else
                                    If csy < 0 And csx >= 0 Then
                                        tangle = Int((Atn(csy / csx) + 2 * 3.1415926) / 3.1415926 * 180)
                                    End If
                                End If
                            End If
                        Else
                            tangle = 0
                        End If                    If basicrecord(tangle, 0) >= Sqr(csx ^ 2 + csy ^ 2) Then '判断中心是否出了basicrecord
                             Picture1.Cls
                              showcom
                              showtem
                                For k = 0 To 360
                                    cangle = (k + 90) * pi180
                                    cy = (temrecord(k, 0)) * Sin(k * pi180) + csx
                                    cx = (temrecord(k, 0)) * Cos(k * pi180) + csy                                jl = Sqr((cx - temrecord2(k, 1)) ^ 2 + (cy - temrecord2(k, 0)) ^ 2)
                                    If jl > Val(Text7.Text) Then'text7.text为容差值
                                        count = count + 1
                                    End If
                                   If count > 180 Then Exit For
                                  Next
                                DoEvents                    End If
                      Next
                Next
            Next
      

  5.   

    你的循环嵌套太多,内层又有大量的浮点乘法、三角函数。  ①至少有一个优化方案是:
      把 0°~ 360°的正弦、余弦函数值预先处理,分别对应保存在一个 Double 类型的、下标为 0~360 的一维数组中,使用时直接以度数为下标,在数组中取值。
      这个方法应该能大大提高速度。  ②你的变量声明方式不正确。产生了大量的 Variant 类型的变量,这很影响速度。  ③建议所有的变量,整数类型的都用 Long;Single 类型的都用 Double 。
      特别是 Single 类型,可能很多人都不知道:在VB中,即使只有 Single 类型的数据参与运算,运算时也要先全部转换成 Double ,运算后再将结果转换成 Single 来赋值(当然赋值给 Double 类型的变量就不会再转了)。  ④9F 的第一项。
      

  6.   

    所有的 X ^2 都改成 X*X
    也能大大提高速度。
      

  7.   

    ........
    If jl > Val(Text7.Text) Then 
    ..........Text7.Text 在整个过程中没有发生过变化,在进入第一层循环前,就用一个合适类型的变量保存它的值。在 If 语句中使用那个变量。本来转换一次就行的,何苦要它转换 360^4 = 16796160000次(最坏的情况,约168亿次啊)? 这浪费多少时间!!!
      

  8.   


    有声明的?
    是有声明,但不正确。
    你的“Dim i, j, k, l, f As Integer 
    只有 f 是 Integer,其余四个都是 Variant 类型。
      

  9.   

    你会用API吗? 找一个图形旋转的API就搞定了,还算什么?
    '================== 旋转图形用 ========================================
      Public Type POINTS2D
               X As Long
               Y As Long
             End Type
      Public Const NotPi = 3.14159265238 / 180                    '每度的弧度数
      Public Const Pi = 3.14159265238
      Public Declare Function PlgBlt Lib "gdi32" (ByVal hdcDest As Long, lpPoint As POINTS2D, _
                   ByVal hdcSrc As Long, ByVal nXSrc As Long, _
                   ByVal nYSrc As Long, ByVal nWidth As Long, _
                   ByVal nHeight As Long, ByVal hbmMask As Long, _
                   ByVal xMask As Long, ByVal yMask As Long) As LongSub D中心转(ByRef picDestHdc As Long, xPos As Long, yPos As Long, Fd As Single, _
               ByVal Angle As Long, ByRef picSrcHdc As Long, _
               srcXoffset As Long, srcYoffset As Long, _
               ByVal srcWidth As Long, ByVal srcHeight As Long)
       ' picDestHdc: 目标,  xPos、yPos 中心坐标
       ' Fd 放大倍数   Angle 旋转角度
       ' srcYoffset: 源图,srcXoffset、srcYoffset、srcWidth、srcHeight 矩形范围
        
        Dim points(3) As POINTS2D
        Dim DefPoints(3) As POINTS2D
        Dim ThetS As Single, ThetC As Single
        Dim Ret As Long
     
        points(0).X = -srcWidth * 0.5 * Fd
        points(0).Y = -srcHeight * 0.5 * Fd
        points(1).X = points(0).X + srcWidth * Fd
        points(1).Y = points(0).Y
        points(2).X = points(0).X
        points(2).Y = points(0).Y + srcHeight * Fd
     
        ThetS = Sin(Angle * NotPi)
        ThetC = Cos(Angle * NotPi)
     
        DefPoints(0).X = (points(0).X * ThetC - points(0).Y * ThetS) + xPos
        DefPoints(0).Y = (points(0).X * ThetS + points(0).Y * ThetC) + yPos
        DefPoints(1).X = (points(1).X * ThetC - points(1).Y * ThetS) + xPos
        DefPoints(1).Y = (points(1).X * ThetS + points(1).Y * ThetC) + yPos
        DefPoints(2).X = (points(2).X * ThetC - points(2).Y * ThetS) + xPos
        DefPoints(2).Y = (points(2).X * ThetS + points(2).Y * ThetC) + yPos
     
        PlgBlt picDestHdc, DefPoints(0), picSrcHdc, srcXoffset, srcYoffset, _
               srcWidth, srcHeight, 0, 0, 0
    End Sub
      

  10.   

    Chen8013 的建议果然不错,速度提升了不少,但还是不够,不过现在对一些不必要的情况进行了排除,现在只需要一分钟不到了。谢谢各位了!!!我是学硬件的,VB只是自学的,到现在也很久了,不过学的也比较表面。这次遇到要图像处理,没想到会那么费时间。
      

  11.   


    溜墙边偷偷插嘴问chen,你的圈1圈2圈3圈4,是怎么敲出来的?
      

  12.   

    首先你要明白,编译系统不是绝对聪明的,我相信它不会把 X^2 转换成 X*X。
    你既然用的幂运算符,它就会按幂运算的方式来计算这个表达式。
    幂如何运算?CPU能直接进行幂运算吗?
    不能!秘密就是自然对数的底 e !!!你可以试一下简单的测试:
    '(一个窗体,上面两个按钮、一个标签)
    Option ExplicitPrivate Sub Command1_Click()
        Dim i&, Q&, n&, t#
        t = Timer()
        n = 4506
        For i = 1 To 15000000
            Q = n ^ 2
        Next
        Label1.Caption = Timer() - t
    End SubPrivate Sub Command2_Click()
        Dim i&, Q&, n&, t#
        t = Timer()
        n = 4506
        For i = 1 To 15000000
            Q = n * n
        Next
        Label1.Caption = Timer() - t
    End Sub指数运算耗时是乘法运算的100倍左右。我常用的智能陈桥。
    要进行特殊的输入时,切换到王码五笔或全拼就可以了,它有软键盘,在上面点鼠标右键......
      

  13.   

    laviewpbt 兄这是我的QQ:409459713
    您加我,或者您留个mail或Q吧~
      

  14.   

    vb 要想速度快需要把握几个最最基本的原则:
    ㈠ 正确的变量声明,能使integer型就不要用long型,能使long型就不double
    ㈡ 尽量采用低级运算,如可以提前拆分的能加减不乘除,虽然这样会在写公式前算一下,不过会提高速度
    ㈢ 正确的或优化的算法
      

  15.   

    我把我的代码贴出来吧~没必要的部分给删除了只需要一个窗体,一个文本框,一个按钮,一个lable,一个pictureDim sinvalue(360) As Double
    Dim cosvalue(360) As Double
    Dim record(360, 1) As Long, basicrecord(360, 1) As Long, temrecord(360, 1) As Long
    Dim X As Long, delayt As Byte, scanspeed As Double, rad, maxv As Long, stops As Boolean, pw As Long, ph As Long, PWW As Long, PHH As Long, pi As Single, pi180 As Single
    Public Sub showtem()
    Dim i As Integer
    Dim sxx, syy, sxx1, syy1 As LongFor i = 0 To 360
        If temrecord(i, 1) = 1 Then
            j = pi180 * (i + 90)
            sxx = (temrecord(i, 0) / maxv / 10) * (rad) * Sin(j) + pw
            syy = (temrecord(i, 0) / maxv / 10) * (rad) * Cos(j) + ph
            Picture1.PSet (sxx, syy), vbBlue
             If sxx1 <> 0 And syy1 <> 0 Then Picture1.Line (sxx, syy)-(sxx1, syy1), vbBlue
            sxx1 = sxx
            syy1 = syy
        End If
    Next
    End SubPublic Sub showcom()
    Dim i As Integer
    Dim sxx, syy, sxx1, syy1 As LongFor i = 0 To 360
        If basicrecord(i, 1) = 1 Then
            j = pi180 * (i + 90)
            sxx = (basicrecord(i, 0) / maxv / 10) * (rad) * Sin(j) + pw
            syy = (basicrecord(i, 0) / maxv / 10) * (rad) * Cos(j) + ph
            Picture1.PSet (sxx, syy), vbWhite
             If sxx1 <> 0 And syy1 <> 0 Then Picture1.Line (sxx, syy)-(sxx1, syy1), vbWhite
            sxx1 = sxx
            syy1 = syy
        End If
    Next
    End SubPublic Sub showrecord()
    Dim i As Integer
    Dim sxx, syy, sxx1, syy1 As LongPicture1.Cls
    For i = 0 To 360
        If record(i, 1) = 1 Then
            j = pi180 * (i + 90)
            sxx = (record(i, 0) / maxv / 10) * (rad) * Sin(j) + pw
            syy = (record(i, 0) / maxv / 10) * (rad) * Cos(j) + ph
            Picture1.PSet (sxx, syy), vbRed
             If sxx1 <> 0 And syy1 <> 0 Then Picture1.Line (sxx, syy)-(sxx1, syy1), vbRed
            sxx1 = sxx
            syy1 = syy
        End If
    Next
    End Sub
    Private Sub Command1_Click()
    Dim temrecord2(360, 1) As Long
    Dim i As Long, j As Long, k As Long, l As Long, f As Long
    Dim count As Long
    Dim cx As Long, cy As Long, csx As Long, csy As Long
    Dim bcy As Double, bcx As Double
    Dim jl As Double
    Dim tangle As Long
    Dim tolerance As Long
    Dim p180 As Double
    Dim maxcount As Long
    contimerc = 0 tolerance = Val(Text1.Text)For l = 0 To 360
            temrecord2(l, 0) = (basicrecord(l, 0)) * sinvalue(l)
            temrecord2(l, 1) = (basicrecord(l, 0)) * cosvalue(l)
    Next        For l = 0 To 360
                For i = 0 To 360
                      If i - l < 0 Then
                            temrecord(i, 0) = record(i - l + 360, 0)
                        Else
                            temrecord(i, 0) = record(i - l, 0)
                        End If
                        temrecord(i, 1) = 1
                Next
                            
                For f = 0 To 360
                    bcy = basicrecord(f, 0) * sinvalue(f)
                    bcx = basicrecord(f, 0) * cosvalue(f)
                    For j = 0 To 360
                        contimerc = contimerc + 1
                        csx = Int((bcx - temrecord(j, 0) * cosvalue(j)))
                        csy = Int((bcy - temrecord(j, 0) * sinvalue(j)))
                        count = 0                    If csx <> 0 Then '获取圆心移动的角度
                            If csy >= 0 And csx >= 0 Then
                                tangle = Int(Atn(csy / csx) / 3.1415926 * 180)
                            Else
                                If csx < 0 Then
                                    tangle = Int((Atn(csy / csx) + 3.1415926) / 3.1415926 * 180)
                                Else
                                    If csy < 0 And csx >= 0 Then
                                        tangle = Int((Atn(csy / csx) + 2 * 3.1415926) / 3.1415926 * 180)
                                    End If
                                End If
                            End If
                        Else
                            tangle = 0
                        End If                    If basicrecord(tangle, 0) >= Sqr(csx * csx + csy * csy) Then '判断中心是否出了basicrecord
                             
                           Picture1.Cls
                              showcom
                         showtem                            For k = 0 To 360
                                    cangle = (k + 90) * pi180
                                    cy = (temrecord(k, 0)) * sinvalue(k) + csx
                                    cx = (temrecord(k, 0)) * cosvalue(k) + csy
                                    Picture1.PSet (sxx, syy), vbBlue
                                   sxx = (temrecord(k, 0) / maxv / 10) * (rad) * Sin(cangle) + pw + csx / maxv / 10 * rad
                                    syy = (temrecord(k, 0) / maxv / 10) * (rad) * Cos(cangle) + ph + csy / maxv / 10 * rad
                                     If sxx1 <> 0 And syy1 <> 0 Then Picture1.Line (sxx, syy)-(sxx1, syy1), vbBlue
                                    sxx1 = sxx
                                    syy1 = syy
                                    jl = Sqr((cx - temrecord2(k, 1)) ^ 2 + (cy - temrecord2(k, 0)) ^ 2)
                                    If jl > tolerance Then
                                        count = count + 1
                                    End If
                                   If count > 180 Then Exit For
                                  Next
                                  If maxcount > count Then
                                    maxcount = count
                                 End If
                                DoEvents
                                Debug.Print Str((360 - count) / 360 * 100) + "%:::::::::" + Str(j) + "::::::::::" + Str(f) + "::::::::::::" + Str(l)
                        End If
                      Next
                Next
            Next
               Label1.Caption = 360 - maxcount
    End SubPrivate Sub Form_Load()rad = Picture1.Width / 2 - 58
    maxv = 500
    pw = Picture1.Width / 2
    ph = Picture1.Height / 2
    pi180 = 3.1415926 / 180For i = 0 To 180
        basicrecord(i, 0) = i * 20
        basicrecord(i, 1) = 1
        record(i, 0) = (180 - i) * 20
        record(i, 1) = 1
    Next
    For i = 181 To 360
        basicrecord(i, 0) = (180 - (i - 180)) * 20
        basicrecord(i, 1) = 1
        record(i, 0) = (i - 180) * 20
        record(i, 1) = 1
    Next
    For l = 0 To 360
        sinvalue(l) = Sin(pi180 * l)
        cosvalue(l) = Cos(pi180 * l)
    Next
    End Sub
      

  16.   

    画图部分可以不要
    只是为了表示运算过程才画图的下面这些代码可以不要
                          Picture1.Cls 
                        showcom 
                        showtem                                Picture1.PSet (sxx, syy), vbBlue 
                                  sxx = (temrecord(k, 0) / maxv / 10) * (rad) * Sin(cangle) + pw + csx / maxv / 10 * rad 
                                    syy = (temrecord(k, 0) / maxv / 10) * (rad) * Cos(cangle) + ph + csy / maxv / 10 * rad 
                                    If sxx1 <> 0 And syy1 <> 0 Then Picture1.Line (sxx, syy)-(sxx1, syy1), vbBlue 
                                    sxx1 = sxx 
                                    syy1 = syy 
      

  17.   

    第一条前半部分是错误的
    在32位操作系统上,4字节的long型变量是最快的
    所以,应该是“能使用long就不适用integer”
      

  18.   


    要1个小时?
    多大的图片呀?有这么慢吗~~~~ -_-!可不可以弄两三张图片,打个压缩包发给我看一看呀?
    E_Mail: [email protected]
      

  19.   

    推荐一下这个帖子,向modest或者葛润鬓。
      

  20.   


    “能使用long就不用integer”
    这个是真的吗?我的计算程序可以全部更换了。从这个帖子学到了很多。
      

  21.   

    回63楼
    参看MSDN“代码优化”部分:使用 Long 整型变量和整数运算
    算术运算中要避免使用 Currency、Single 和 Double 变量;并尽量使用 Long 整型变量,尤其在循环体中。因为 Long 整数是 32 位 CPU 的本机数据类型,所以其操作非常快;如果无法使用 Long 变量,就要尽量使用 Integer 或 Byte 数据类型。很多时候,即使在要求使用浮点数的情况下,也可以使用 Long 整数。例如,在窗体和图形控件的 ScaleMode 属性设置为缇或象素时,就可以在控件和图形方法中使用 Long 整型变量表示大小和位置。进行除法运算时,如果不需要小数部分,就可以使用整数除法运算符 (/)。由于浮点运算需要转移到协处理器上进行,而整数运算并不需要,所以整数运算总是比浮点运算快。如果确实需要做小数运算,则 Double 数据类型比 Currency 数据类型快。下表把各种数值数据类型按运算速度顺序列出。数值数据类型 速度 
    Long 最快 
    Integer .
     
    Byte .
     
    Single .
     
    Double .
     
    Currency 最慢 
      

  22.   

    重复计算太多!temp=(temrecord(k, 0) / maxv / 10)sin 与 cos 是有关系的,变成一个运算。 If i - l < 0 Then 
      temrecord(i, 0) = record(i - l + 360, 0) 
       Else 
       temrecord(i, 0) = record(i… 想一下概率吧!那个该放前面减少判断。
      

  23.   

    f,j,k循环中没有用到l循环,可单独拿出来!这就少了一层循环嘛!
      

  24.   

    我已经把sin cos 能先运算的,先运算并保存在数组中了,用到是就从数组中拿出来用。
    现在还需要40分钟左右啊
      

  25.   


    楼主的算法思路是否这样的:将一幅图旋转某一角度,与另一幅图比对?其实应该分两阶段来做:
    1 首先选取 A 图几个点,做旋转映射,与 B 图比对。算一个,比一个,有一个不同,就跳出到下一个角度。只有全部相同,才进入下一步。
    2 对你做相同判断所需的所有点,做旋转映射和比对。只要有一个不同,就跳出到下一个角度。也许要更好的算法,不需要这样一一比对。另外,如果 B 图是 A 图非整数角度的旋转映射,又怎么办?
      

  26.   

    把DoEvents去掉。这个只会降低效率增长处理时间。
      

  27.   

    另外,类似于Cos(j * pi180)这些最好使用常量