-1

私はこのコードを数日間より速く、より効率的にしようと試みてきましたが、それでもそれができるほど効率的ではないようです。

Sub Main()
    Dim watch As Stopwatch = Stopwatch.StartNew()

    Dim l As New List(Of ULong)(CType(My.Application.CommandLineArgs.Item(0), ULong))
    For i As ULong = 1 To l.Capacity
        ' ONE LINE IF STMT: If l.Capacity And 1 <> 0 Then If i And 1 = 0 Then l.Add((i * i) - 1) Else l.Add((i * i) + 1) Else If i And 1 = 0 Then l.Add((i * i) + 1) Else l.Add((i * i) - 1)
        If l.Capacity And 1 <> 0 Then
            If i And 1 = 0 Then
                l.Add((i * i) - 1)
            Else
                l.Add((i * i) + 1)
            End If
        Else
            If i And 1 = 0 Then
                l.Add((i * i) + 1)
            Else
                l.Add((i * i) - 1)
            End If
        End If
    Next i
    Console.WriteLine(String.Join(","c, l.ToArray))

    watch.Stop()
    Console.WriteLine(watch.Elapsed.TotalMilliseconds)
    Console.ReadLine()
End Sub

現在、4.3ミリ秒でiを100回繰り返し実行しています。ここでは、ネストされたifステートメントが主なボトルネックのように感じますが、それらを変更する方法がわかりません。

では、このコードをより効率的にすることはできますか?

ありがとう... :)

4

2 に答える 2

1

最初If l.Capacity And 1 <> 0に、ループから抜け出します。これは常に同じになるためです。

次に、より読みやすいテストを優先してビット操作を削除しi Mod 2 = 0ます。これはより効率的であると考えているようですが、実際には、そのような些細な最適化はコンパイラとランタイムに任せるのが最善です。コードには場所がありません。測定可能な影響があります

それでも効率が悪い場合は、初期容量と を使用しないでくださいAdd。代わりにResize、要素へのインデックス付きアクセスを使用してください。If次に、偶数要素用と奇数要素用の 2 つのループを使用して、他のステートメントを取り除くこともできます。

とは言っても、ここでJoin操作はおそらく最も遅いステップであり (おそらくコンソールへの実際の出力を除けば)、それを最適化するためにできることは何もありません。

最後に、恐ろしく判読できないことがわかりましたCType。ここで行っていることは、キャストではなく、解析操作です。なぜそれを1つとして書かないのですか?ULong.Parse(…). My.Application.CommandLineArgs.Itemまた、コマンドライン引数をパラメーターとして受け入れるのではなく、扱いにくいものを使用するのはなぜMainですか?

于 2012-07-28T12:01:49.130 に答える
0

エラーのみを修正すると、リリース ビルドの Visual Studio 2010 で Ctrl+F5 を使用すると、次の出力が得られます。

0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208, 2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185, 5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408, 9605,9800,10001
33.9106

それはこのコードです:

Sub Main()
    Dim watch As Stopwatch = Stopwatch.StartNew()

    Dim l As New List(Of ULong)(CInt(My.Application.CommandLineArgs(0)))

    For i As ULong = 1 To CULng(l.Capacity)
        ' ONE LINE IF STMT: If l.Capacity And 1 <> 0 Then If i And 1 = 0 Then l.Add((i * i) - 1) Else l.Add((i * i) + 1) Else If i And 1 = 0 Then l.Add((i * i) + 1) Else l.Add((i * i) - 1)
        If (l.Capacity And 1) <> 0 Then
            If (i And 1UL) = 0UL Then
                l.Add((i * i) - 1UL)
            Else
                l.Add((i * i) + 1UL)
            End If
        Else
            If (i And 1UL) = 0UL Then
                l.Add((i * i) + 1UL)
            Else
                l.Add((i * i) - 1UL)
            End If
        End If
    Next i
    Console.WriteLine(String.Join(","c, l.ToArray))

    watch.Stop()
    Console.WriteLine(watch.Elapsed.TotalMilliseconds)
    Console.ReadLine()
End Sub

LINQ の使用:

0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208, 2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185, 5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408, 9605,9800,10001
13.0721

それは次のとおりです。

Sub Main()
    Dim watch As Stopwatch = Stopwatch.StartNew()

    Dim arg = CInt(My.Application.CommandLineArgs(0))
    Console.WriteLine(String.Join(","c, Enumerable.Range(1, arg).Select(
                                  Function(i) ((i * i +
                                               If((arg And 1) <> 0,
                                                   If((i And 1) = 0, -1, 1),
                                                   If((i And 1) = 0, 1, -1))).ToString()))))

    watch.Stop()
    Console.WriteLine(watch.Elapsed.TotalMilliseconds)
    Console.ReadLine()
End Sub

最適化されました:

0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208, 2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185, 5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408, 9605,9800,10001
12.5956

そして、この時点で、私は明らかにConsole.WriteLine分散がタイミング内にあると思っていましたが、以下のコードを使用しても、まだ 12 ~ 15 ミリ秒かかります...

Sub Main()
    Dim watch As Stopwatch = Stopwatch.StartNew()

    Dim arg = CInt(My.Application.CommandLineArgs(0))

    Dim fn As Func(Of Integer, String) = If((arg And 1) <> 0,
                                            Function(i As Integer) ((i * i + If((i And 1) = 0, -1, 1)).ToString()),
                                            Function(i As Integer) ((i * i + If((i And 1) = 0, 1, -1)).ToString()))

    Dim s = String.Join(","c, Enumerable.Range(1, arg).Select(fn))

    watch.Stop()
    Console.WriteLine(s)
    Console.WriteLine(watch.Elapsed.TotalMilliseconds)
    Console.ReadLine()
End Sub
于 2012-07-30T08:32:34.200 に答える