0

以下は、VB.NET (Visual Studio 2010、.NET Framework 4) の Parallel.for ループ内にネストされたループ内で実行中の合計を計算するために開発できた最良の表現です。結果を「合計」で画面に表示する場合、2 つの合計にはわずかな違いがあるため、並列化されたバリアントでは情報が失われることに注意してください。では、どのように情報が失われ、何が起こっているのでしょうか? このコンテキストで現在の金額を維持するための方法論について、誰かが「顕微手術」を提供できますか? (Parallel.for の新規ユーザーへの注意: 通常、0 から始まるメソッドは使用しないため、Parallel.for ステートメントでは、コードが上限として 101-1 を使用するため、I1 は 101 までループします。これは、 MS は、ゼロベースのカウンターを想定して並列コードを開発しました):

    Dim sum As Double = 0
    Dim lock As New Object
    Dim clock As New Stopwatch
    Dim i, j As Integer
    clock.Start()
    sum = 0
    For i = 1 To 100
        For j = 1 To 100
            sum += Math.Log(0.9999)
        Next j
    Next i
    clock.Stop()
    MsgBox(sum & "  " & clock.ElapsedMilliseconds)
    sum = 0
    clock.Reset()
    clock.Start()
    Parallel.For(1, 101, Sub(i1)
                             Dim temp As Double = 0
                             For j1 As Integer = 1 To 100
                                 temp += Math.Log(0.9999)
                             Next
                             SyncLock lock
                                 sum += temp
                             End SyncLock
                         End Sub)
    clock.Stop()
    MsgBox(sum & "  " & clock.ElapsedMilliseconds)    
4

1 に答える 1

0

double を使用していますが、double は単に正確ではありません。非並列ループでは、すべてのエラーが合計に直接格納されます。並列ループには、後で合計に追加される追加の tmp があります。非並列ループで同じ tmp を使用すると (内側のループが実行された後に合計に追加されます)、最終的に結果は等しくなります。

 Dim sum As Double = 0
    Dim lock As New Object
    Dim clock As New Stopwatch
    Dim i, j As Integer
    clock.Start()
    sum = 0
    For i = 1 To 100
        For j = 1 To 100
            sum += Math.Log(0.9999)
        Next j
    Next i
    clock.Stop()
    Console.WriteLine(sum & "  " & clock.ElapsedMilliseconds)
    sum = 0
    clock.Reset()

    clock.Start()
    sum = 0
    For i = 1 To 100
        Dim tmp As Double = 0
        For j = 1 To 100
            tmp += Math.Log(0.9999)
        Next
        sum += tmp
    Next i
    clock.Stop()
    Console.WriteLine(sum & "  " & clock.ElapsedMilliseconds)
    sum = 0
    clock.Reset()

    clock.Start()
    Parallel.For(1, 101, Sub(i1)
                             Dim temp As Double = 0
                             For j1 As Integer = 1 To 100
                                 temp += Math.Log(0.9999)
                             Next
                             SyncLock lock
                                 sum += temp
                             End SyncLock
                         End Sub)
    clock.Stop()
    Console.WriteLine(sum & "  " & clock.ElapsedMilliseconds)

End Sub

出力:

-1,00005000333357  0
-1,00005000333347  0
-1,00005000333347  26

結論: double を使用する場合、(a + b) + c は (常に) a + (b + c) と等しくありません

アップデート

さらに簡単な例:

    Dim sum As Double
    For i = 1 To 100
        sum += 0.1
    Next
    Console.WriteLine(sum)

    sum = 0
    For i = 1 To 2
        Dim tmp As Double = 0
        For j = 1 To 50
            tmp += 0.1
        Next
        sum += tmp
    Next
    Console.WriteLine(sum)

今、出力は

9,99999999999998
10
于 2012-11-28T16:49:36.220 に答える