最後に、数学者に相談したところ、彼はすぐに正しい公式を見つけ出しました。これは、私が自分で試していたものと非常によく似ていましたが、それでもわずかに異なっていました. これにより、入力数値が完全に更新されると同時に、手書きのステップでのみ補因子を更新できました。
しかし、驚いたことに、この対策だけではパフォーマンスへの影響は軽微でした。「融合(A×X + B×Y)」として再実装したときだけ、速度の向上が顕著になりました。両方の余因子を計算すると、純粋な Lehmer GCD アルゴリズムと比較して、5 桁の数値の場合は 56 %、32K 桁の場合は 34 % で実行されます。単一の補因子の場合、割合はそれぞれ 70 % と 52 % です。以前の実装では、両方の補因子で 33% から 7%、単一の補因子で 47% から 14% にすぎなかったため、私の不満は明らかでした。
他の実装者が同じトラブルを起こさないようにandy256が推奨するように論文を書くことは簡単ではありません。現在の実装を数学者に説明するときに、私はすでに「小さな」論文を書きましたが、A4 サイズのシート 3 枚をあっという間に超えてしまいました — 詳細な説明、オーバーフロー チェック、分岐、展開などを除いて、基本的なアイデアのみが含まれています。クヌースや他の人々が話を短くするために汚いトリックを使った理由を部分的に理解する. 現在、完全性を失わずに同じレベルの単純さを達成する方法がわかりません。おそらく、コメントと組み合わせたいくつかの大きなフローチャートが必要になるでしょう。
更新します。近いうちにライブラリを完成させて公開することはできそうにない (まだニュートン (ラフソン除算とモンゴメリー削減) を理解するのはうまくいかない) ので、興味のある人のために結果の関数を投稿するだけにします。
ComputeGCD_Euclid
コードには、 のような明らかな関数や、 のような汎用ルーチンは含まれていませんComputeDivisionLonghand
。コードにはコメントもありません (いくつかの例外を除いて) — それを理解して自分のライブラリに統合したいのであれば、Lehmer の一般的な考え方と上記の 2 桁の省略形の手法については既によく知っているはずです。
私のライブラリでの数値表現の概要。数字は 32 ビットの符号なし整数であるため、必要に応じて 64 ビットの符号なしおよび符号付き演算を使用できます。数字は単純な配列 ( ValueDigits
) に最下位から最上位 (LSB) まで格納され、実際のサイズは明示的に格納されます ( ValueLength
)。つまり、関数は結果のサイズを予測しようとしますが、計算後のメモリ消費を最適化しません。オブジェクトは値型 ( struct
.Net 内) ですが、数字配列を参照します。したがって、オブジェクトは不変です。つまりa = a + 1
、既存のオブジェクトを変更する代わりに、新しいオブジェクトを作成します。
Public Shared Function ComputeGCD(ByVal uLeft As BigUInteger, ByVal uRight As BigUInteger,
ByRef uLeftInverse As BigUInteger, ByRef uRightInverse As BigUInteger, ByVal fComputeLeftInverse As Boolean, ByVal fComputeRightInverse As Boolean) As BigUInteger
Dim fSwap As Boolean = False
Select Case uLeft.CompareTo(uRight)
Case 0
uLeftInverse = Instance.Zero : uRightInverse = Instance.One : Return uRight
Case Is < 0
fSwap = fComputeLeftInverse : fComputeLeftInverse = fComputeRightInverse : fComputeRightInverse = fSwap
fSwap = True : Swap(uLeft, uRight)
End Select
Dim uResult As BigUInteger
If (uLeft.ValueLength = 1) AndAlso (uRight.ValueLength = 1) Then
Dim wLeftInverse As UInt32, wRightInverse As UInt32
uResult = ComputeGCD_Euclid(uLeft.DigitLowest, uRight.DigitLowest, wLeftInverse, wRightInverse)
uLeftInverse = wLeftInverse : uRightInverse = wRightInverse
ElseIf uLeft.ValueLength <= 2 Then
uResult = ComputeGCD_Euclid(uLeft, uRight, uLeftInverse, uRightInverse)
Else
uResult = ComputeGCD_Lehmer(uLeft, uRight, uLeftInverse, uRightInverse, fComputeLeftInverse, fComputeRightInverse)
End If
If fSwap Then Swap(uLeftInverse, uRightInverse)
Return uResult
End Function
Private Shared Function ComputeGCD_Lehmer(ByVal uLeft As BigUInteger, ByVal uRight As BigUInteger,
ByRef uLeftInverse As BigUInteger, ByRef uRightInverse As BigUInteger, ByVal fComputeLeftInverse As Boolean, ByVal fComputeRightInverse As Boolean) As BigUInteger
Dim uLeftCur As BigUInteger = uLeft, uRightCur As BigUInteger = uRight
Dim uLeftInvPrev As BigUInteger = Instance.One, uRightInvPrev As BigUInteger = Instance.Zero,
uLeftInvCur As BigUInteger = uRightInvPrev, uRightInvCur As BigUInteger = uLeftInvPrev,
fInvInit As Boolean = False, fIterationIsEven As Boolean = True
Dim dwLeftCur, dwRightCur As UInt64
Dim wLeftInvPrev, wRightInvPrev, wLeftInvCur, wRightInvCur As UInt32
Dim dwNumeratorMore, dwNumeratorLess, dwDenominatorMore, dwDenominatorLess, dwQuotientMore, dwQuotientLess As UInt64,
wQuotient As UInt32
Const nSubtractionThresholdBits As Byte = (5 - 1)
Dim ndxDigitMax As Integer, fRightIsShorter As Boolean
Dim fResultFound As Boolean = False
Dim uRemainder As BigUInteger = uRightCur, uQuotient As BigUInteger
Dim uTemp As BigUInteger = Nothing, dwTemp, dwTemp2 As UInt64
Do While uLeftCur.ValueLength > 2
ndxDigitMax = uLeftCur.ValueLength - 1 : fRightIsShorter = (uRightCur.ValueLength < uLeftCur.ValueLength)
Dim fShorthandStep As Boolean = True, fShorthandIterationIsEven As Boolean
If fRightIsShorter AndAlso (uLeftCur.ValueLength - uRightCur.ValueLength > 1) Then fShorthandStep = False
If fShorthandStep Then
dwLeftCur = uLeftCur.ValueDigits(ndxDigitMax - 1) Or (CULng(uLeftCur.ValueDigits(ndxDigitMax)) << DigitSize.Bits)
dwRightCur = uRightCur.ValueDigits(ndxDigitMax - 1) Or If(fRightIsShorter, DigitValue.Zero, CULng(uRightCur.ValueDigits(ndxDigitMax)) << DigitSize.Bits)
If ndxDigitMax >= 2 Then
Dim nNormHead As Byte = GetNormalizationHead(uLeftCur.ValueDigits(ndxDigitMax))
If nNormHead <> ByteValue.Zero Then
dwLeftCur = (dwLeftCur << nNormHead) Or (uLeftCur.ValueDigits(ndxDigitMax - 2) >> (DigitSize.Bits - nNormHead))
dwRightCur = (dwRightCur << nNormHead) Or (uRightCur.ValueDigits(ndxDigitMax - 2) >> (DigitSize.Bits - nNormHead))
End If
End If
If CUInt(dwRightCur >> DigitSize.Bits) = DigitValue.Zero Then fShorthandStep = False
End If
If fShorthandStep Then
' First iteration, where overflow may occur in general formulae.
If dwLeftCur = dwRightCur Then
fShorthandStep = False
Else
If dwLeftCur = DoubleValue.Full Then dwLeftCur >>= 1 : dwRightCur >>= 1
dwDenominatorMore = dwRightCur : dwDenominatorLess = dwRightCur + DigitValue.One
dwNumeratorMore = dwLeftCur + DigitValue.One : dwNumeratorLess = dwLeftCur
If (dwNumeratorMore >> nSubtractionThresholdBits) <= dwDenominatorMore Then
wQuotient = DigitValue.Zero
Do
wQuotient += DigitValue.One : dwNumeratorMore -= dwDenominatorMore
Loop While dwNumeratorMore >= dwDenominatorMore
dwQuotientMore = wQuotient
Else
dwQuotientMore = dwNumeratorMore \ dwDenominatorMore
If dwQuotientMore >= DigitValue.BitHi Then fShorthandStep = False
wQuotient = CUInt(dwQuotientMore)
End If
If fShorthandStep Then
If (dwNumeratorLess >> nSubtractionThresholdBits) <= dwDenominatorLess Then
wQuotient = DigitValue.Zero
Do
wQuotient += DigitValue.One : dwNumeratorLess -= dwDenominatorLess
Loop While dwNumeratorLess >= dwDenominatorLess
dwQuotientLess = wQuotient
Else
dwQuotientLess = dwNumeratorLess \ dwDenominatorLess
End If
If dwQuotientMore <> dwQuotientLess Then fShorthandStep = False
End If
End If
End If
If fShorthandStep Then
' Prepare for the second iteration.
wLeftInvPrev = DigitValue.Zero : wLeftInvCur = DigitValue.One
wRightInvPrev = DigitValue.One : wRightInvCur = wQuotient
dwTemp = dwLeftCur - wQuotient * dwRightCur : dwLeftCur = dwRightCur : dwRightCur = dwTemp
fShorthandIterationIsEven = True
fIterationIsEven = Not fIterationIsEven
' Other iterations, no overflow possible(?).
Do
If fShorthandIterationIsEven Then
If dwRightCur = wRightInvCur Then Exit Do
dwDenominatorMore = dwRightCur - wRightInvCur : dwDenominatorLess = dwRightCur + wLeftInvCur
dwNumeratorMore = dwLeftCur + wRightInvPrev : dwNumeratorLess = dwLeftCur - wLeftInvPrev
Else
If dwRightCur = wLeftInvCur Then Exit Do
dwDenominatorMore = dwRightCur - wLeftInvCur : dwDenominatorLess = dwRightCur + wRightInvCur
dwNumeratorMore = dwLeftCur + wLeftInvPrev : dwNumeratorLess = dwLeftCur - wRightInvPrev
End If
If (dwNumeratorMore >> nSubtractionThresholdBits) <= dwDenominatorMore Then
wQuotient = DigitValue.Zero
Do
wQuotient += DigitValue.One : dwNumeratorMore -= dwDenominatorMore
Loop While dwNumeratorMore >= dwDenominatorMore
dwQuotientMore = wQuotient
Else
dwQuotientMore = dwNumeratorMore \ dwDenominatorMore
If dwQuotientMore >= DigitValue.BitHi Then Exit Do
wQuotient = CUInt(dwQuotientMore)
End If
If (dwNumeratorLess >> nSubtractionThresholdBits) <= dwDenominatorLess Then
wQuotient = DigitValue.Zero
Do
wQuotient += DigitValue.One : dwNumeratorLess -= dwDenominatorLess
Loop While dwNumeratorLess >= dwDenominatorLess
dwQuotientLess = wQuotient
Else
dwQuotientLess = dwNumeratorLess \ dwDenominatorLess
End If
If dwQuotientMore <> dwQuotientLess Then Exit Do
dwTemp = wLeftInvPrev + wQuotient * wLeftInvCur : dwTemp2 = wRightInvPrev + wQuotient * wRightInvCur
If (dwTemp >= DigitValue.BitHi) OrElse (dwTemp2 >= DigitValue.BitHi) Then Exit Do
wLeftInvPrev = wLeftInvCur : wLeftInvCur = CUInt(dwTemp)
wRightInvPrev = wRightInvCur : wRightInvCur = CUInt(dwTemp2)
dwTemp = dwLeftCur - wQuotient * dwRightCur : dwLeftCur = dwRightCur : dwRightCur = dwTemp
fShorthandIterationIsEven = Not fShorthandIterationIsEven
fIterationIsEven = Not fIterationIsEven
Loop
End If
If (Not fShorthandStep) OrElse (wRightInvPrev = DigitValue.Zero) Then
' Longhand step.
uQuotient = ComputeDivisionLonghand(uLeftCur, uRightCur, uTemp) : If uTemp.IsZero Then fResultFound = True : Exit Do
uRemainder = uTemp
fIterationIsEven = Not fIterationIsEven
If fComputeLeftInverse Then
uTemp = uLeftInvPrev + uQuotient * uLeftInvCur : uLeftInvPrev = uLeftInvCur : uLeftInvCur = uTemp
End If
If fComputeRightInverse Then
uTemp = uRightInvPrev + uQuotient * uRightInvCur : uRightInvPrev = uRightInvCur : uRightInvCur = uTemp
End If
fInvInit = True
uLeftCur = uRightCur : uRightCur = uRemainder
Else
' Shorthand step finalization.
If Not fInvInit Then
If fComputeLeftInverse Then uLeftInvPrev = wLeftInvPrev : uLeftInvCur = wLeftInvCur
If fComputeRightInverse Then uRightInvPrev = wRightInvPrev : uRightInvCur = wRightInvCur
fInvInit = True
Else
If fComputeLeftInverse Then ComputeFusedMulMulAdd(uLeftInvPrev, uLeftInvCur, wLeftInvPrev, wLeftInvCur, wRightInvPrev, wRightInvCur)
If fComputeRightInverse Then ComputeFusedMulMulAdd(uRightInvPrev, uRightInvCur, wLeftInvPrev, wLeftInvCur, wRightInvPrev, wRightInvCur)
End If
ComputeFusedMulMulSub(uLeftCur, uRightCur, wLeftInvPrev, wLeftInvCur, wRightInvPrev, wRightInvCur, fShorthandIterationIsEven)
End If
Loop
' Final rounds: numbers are quite short now.
If Not fResultFound Then
ndxDigitMax = uLeftCur.ValueLength - 1 : fRightIsShorter = (uRightCur.ValueLength < uLeftCur.ValueLength)
If ndxDigitMax = 0 Then
dwLeftCur = uLeftCur.ValueDigits(0)
dwRightCur = uRightCur.ValueDigits(0)
Else
dwLeftCur = uLeftCur.ValueDigits(0) Or (CULng(uLeftCur.ValueDigits(1)) << DigitSize.Bits)
dwRightCur = uRightCur.ValueDigits(0) Or If(fRightIsShorter, DigitValue.Zero, CULng(uRightCur.ValueDigits(1)) << DigitSize.Bits)
End If
Do While dwLeftCur >= DigitValue.BitHi
Dim dwRemainder As UInt64 = dwLeftCur
If (dwRemainder >> nSubtractionThresholdBits) <= dwRightCur Then
wQuotient = DigitValue.Zero
Do
wQuotient += DigitValue.One : dwRemainder -= dwRightCur
Loop While dwRemainder >= dwRightCur
dwQuotientMore = wQuotient
Else
dwQuotientMore = dwLeftCur \ dwRightCur
dwRemainder = dwLeftCur - dwQuotientMore * dwRightCur
End If
If dwRemainder = DigitValue.Zero Then fResultFound = True : Exit Do
fIterationIsEven = Not fIterationIsEven
If dwQuotientMore < DigitValue.BitHi Then
wQuotient = CUInt(dwQuotientMore)
If fComputeLeftInverse Then ComputeFusedMulAdd(uLeftInvPrev, uLeftInvCur, wQuotient)
If fComputeRightInverse Then ComputeFusedMulAdd(uRightInvPrev, uRightInvCur, wQuotient)
Else
If fComputeLeftInverse Then
uTemp = uLeftInvPrev + dwQuotientMore * uLeftInvCur : uLeftInvPrev = uLeftInvCur : uLeftInvCur = uTemp
End If
If fComputeRightInverse Then
uTemp = uRightInvPrev + dwQuotientMore * uRightInvCur : uRightInvPrev = uRightInvCur : uRightInvCur = uTemp
End If
End If
dwLeftCur = dwRightCur : dwRightCur = dwRemainder
Loop
If fResultFound Then
uRightCur = dwRightCur
Else
' Final rounds: both numbers have only one digit now, and this digit has MS-bit unset.
Dim wLeftCur As UInt32 = CUInt(dwLeftCur), wRightCur As UInt32 = CUInt(dwRightCur)
Do
Dim wRemainder As UInt32 = wLeftCur
If (wRemainder >> nSubtractionThresholdBits) <= wRightCur Then
wQuotient = DigitValue.Zero
Do
wQuotient += DigitValue.One : wRemainder -= wRightCur
Loop While wRemainder >= wRightCur
Else
wQuotient = wLeftCur \ wRightCur
wRemainder = wLeftCur - wQuotient * wRightCur
End If
If wRemainder = DigitValue.Zero Then fResultFound = True : Exit Do
fIterationIsEven = Not fIterationIsEven
If fComputeLeftInverse Then ComputeFusedMulAdd(uLeftInvPrev, uLeftInvCur, wQuotient)
If fComputeRightInverse Then ComputeFusedMulAdd(uRightInvPrev, uRightInvCur, wQuotient)
wLeftCur = wRightCur : wRightCur = wRemainder
Loop
uRightCur = wRightCur
End If
End If
If fComputeLeftInverse Then
uLeftInverse = If(fIterationIsEven, uRight - uLeftInvCur, uLeftInvCur)
End If
If fComputeRightInverse Then
uRightInverse = If(fIterationIsEven, uRightInvCur, uLeft - uRightInvCur)
End If
Return uRightCur
End Function
''' <remarks>All word-sized parameters must have their most-significant bit unset.</remarks>
Private Shared Sub ComputeFusedMulMulAdd(
ByRef uLeftInvPrev As BigUInteger, ByRef uLeftInvCur As BigUInteger,
ByVal wLeftInvPrev As UInt32, ByVal wLeftInvCur As UInt32, ByVal wRightInvPrev As UInt32, ByVal wRightInvCur As UInt32)
Dim ndxDigitMaxPrev As Integer = uLeftInvPrev.ValueLength - 1, ndxDigitMaxCur As Integer = uLeftInvCur.ValueLength - 1,
ndxDigitMaxNew As Integer = ndxDigitMaxCur + 1
Dim awLeftInvPrev() As UInt32 = uLeftInvPrev.ValueDigits, awLeftInvCur() As UInt32 = uLeftInvCur.ValueDigits
Dim awLeftInvPrevNew(0 To ndxDigitMaxNew) As UInt32, awLeftInvCurNew(0 To ndxDigitMaxNew) As UInt32
Dim dwResult As UInt64, wCarryLeftPrev As UInt32 = DigitValue.Zero, wCarryLeftCur As UInt32 = DigitValue.Zero
Dim wDigitLeftInvPrev, wDigitLeftInvCur As UInt32
For ndxDigit As Integer = 0 To ndxDigitMaxPrev
wDigitLeftInvPrev = awLeftInvPrev(ndxDigit) : wDigitLeftInvCur = awLeftInvCur(ndxDigit)
dwResult = wCarryLeftPrev + wLeftInvPrev * CULng(wDigitLeftInvPrev) + wRightInvPrev * CULng(wDigitLeftInvCur)
awLeftInvPrevNew(ndxDigit) = CUInt(dwResult And DigitValue.Full) : wCarryLeftPrev = CUInt(dwResult >> DigitSize.Bits)
dwResult = wCarryLeftCur + wLeftInvCur * CULng(wDigitLeftInvPrev) + wRightInvCur * CULng(wDigitLeftInvCur)
awLeftInvCurNew(ndxDigit) = CUInt(dwResult And DigitValue.Full) : wCarryLeftCur = CUInt(dwResult >> DigitSize.Bits)
Next
If ndxDigitMaxCur > ndxDigitMaxPrev Then
For ndxDigit As Integer = ndxDigitMaxPrev + 1 To ndxDigitMaxCur
wDigitLeftInvCur = awLeftInvCur(ndxDigit)
dwResult = wCarryLeftPrev + wRightInvPrev * CULng(wDigitLeftInvCur)
awLeftInvPrevNew(ndxDigit) = CUInt(dwResult And DigitValue.Full) : wCarryLeftPrev = CUInt(dwResult >> DigitSize.Bits)
dwResult = wCarryLeftCur + wRightInvCur * CULng(wDigitLeftInvCur)
awLeftInvCurNew(ndxDigit) = CUInt(dwResult And DigitValue.Full) : wCarryLeftCur = CUInt(dwResult >> DigitSize.Bits)
Next
End If
If wCarryLeftPrev <> DigitValue.Zero Then awLeftInvPrevNew(ndxDigitMaxNew) = wCarryLeftPrev
If wCarryLeftCur <> DigitValue.Zero Then awLeftInvCurNew(ndxDigitMaxNew) = wCarryLeftCur
uLeftInvPrev = New BigUInteger(awLeftInvPrevNew) : uLeftInvCur = New BigUInteger(awLeftInvCurNew)
End Sub
''' <remarks>All word-sized parameters must have their most-significant bit unset.</remarks>
Private Shared Sub ComputeFusedMulMulSub(
ByRef uLeftCur As BigUInteger, ByRef uRightCur As BigUInteger,
ByVal wLeftInvPrev As UInt32, ByVal wLeftInvCur As UInt32, ByVal wRightInvPrev As UInt32, ByVal wRightInvCur As UInt32,
ByVal fShorthandIterationIsEven As Boolean)
Dim ndxDigitMax As Integer = uLeftCur.ValueLength - 1,
fRightIsShorter As Boolean = (uRightCur.ValueLength < uLeftCur.ValueLength),
ndxDigitStop As Integer = If(fRightIsShorter, ndxDigitMax - 1, ndxDigitMax)
Dim awLeftCur() As UInt32 = uLeftCur.ValueDigits, awRightCur() As UInt32 = uRightCur.ValueDigits
Dim awLeftNew(0 To ndxDigitMax) As UInt32, awRightNew(0 To ndxDigitStop) As UInt32
Dim iTemp As Int64, wCarryLeft As Int32 = 0I, wCarryRight As Int32 = 0I
Dim wDigitLeftCur, wDigitRightCur As UInt32
If fShorthandIterationIsEven Then
For ndxDigit As Integer = 0 To ndxDigitStop
wDigitLeftCur = awLeftCur(ndxDigit) : wDigitRightCur = awRightCur(ndxDigit)
iTemp = wCarryLeft + CLng(wDigitRightCur) * wRightInvPrev - CLng(wDigitLeftCur) * wLeftInvPrev
awLeftNew(ndxDigit) = CUInt(iTemp And DigitValue.Full) : wCarryLeft = CInt(iTemp >> DigitSize.Bits)
iTemp = wCarryRight + CLng(wDigitLeftCur) * wLeftInvCur - CLng(wDigitRightCur) * wRightInvCur
awRightNew(ndxDigit) = CUInt(iTemp And DigitValue.Full) : wCarryRight = CInt(iTemp >> DigitSize.Bits)
Next
If fRightIsShorter Then
wDigitLeftCur = awLeftCur(ndxDigitMax)
iTemp = wCarryLeft - CLng(wDigitLeftCur) * wLeftInvPrev
awLeftNew(ndxDigitMax) = CUInt(iTemp And DigitValue.Full)
End If
Else
For ndxDigit As Integer = 0 To ndxDigitStop
wDigitLeftCur = awLeftCur(ndxDigit) : wDigitRightCur = awRightCur(ndxDigit)
iTemp = wCarryLeft + CLng(wDigitLeftCur) * wLeftInvPrev - CLng(wDigitRightCur) * wRightInvPrev
awLeftNew(ndxDigit) = CUInt(iTemp And DigitValue.Full) : wCarryLeft = CInt(iTemp >> DigitSize.Bits)
iTemp = wCarryRight + CLng(wDigitRightCur) * wRightInvCur - CLng(wDigitLeftCur) * wLeftInvCur
awRightNew(ndxDigit) = CUInt(iTemp And DigitValue.Full) : wCarryRight = CInt(iTemp >> DigitSize.Bits)
Next
If fRightIsShorter Then
wDigitLeftCur = awLeftCur(ndxDigitMax)
iTemp = wCarryLeft + CLng(wDigitLeftCur) * wLeftInvPrev
awLeftNew(ndxDigitMax) = CUInt(iTemp And DigitValue.Full)
End If
End If
uLeftCur = New BigUInteger(awLeftNew) : uRightCur = New BigUInteger(awRightNew)
End Sub
''' <remarks>All word-sized parameters must have their most-significant bit unset.</remarks>
Private Shared Sub ComputeFusedMulAdd(ByRef uLeftInvPrev As BigUInteger, ByRef uLeftInvCur As BigUInteger, ByVal wQuotient As UInt32)
Dim ndxDigitPrevMax As Integer = uLeftInvPrev.ValueLength - 1, ndxDigitCurMax As Integer = uLeftInvCur.ValueLength - 1,
ndxDigitNewMax As Integer = ndxDigitCurMax + 1
Dim awLeftInvPrev() As UInt32 = uLeftInvPrev.ValueDigits, awLeftInvCur() As UInt32 = uLeftInvCur.ValueDigits,
awLeftInvNew(0 To ndxDigitNewMax) As UInt32
Dim dwResult As UInt64 = DigitValue.Zero, wCarry As UInt32 = DigitValue.Zero
For ndxDigit As Integer = 0 To ndxDigitPrevMax
dwResult = CULng(wCarry) + awLeftInvPrev(ndxDigit) + CULng(wQuotient) * awLeftInvCur(ndxDigit)
awLeftInvNew(ndxDigit) = CUInt(dwResult And DigitValue.Full) : wCarry = CUInt(dwResult >> DigitSize.Bits)
Next
For ndxDigit As Integer = ndxDigitPrevMax + 1 To ndxDigitCurMax
dwResult = CULng(wCarry) + CULng(wQuotient) * awLeftInvCur(ndxDigit)
awLeftInvNew(ndxDigit) = CUInt(dwResult And DigitValue.Full) : wCarry = CUInt(dwResult >> DigitSize.Bits)
Next
If wCarry <> DigitValue.Zero Then awLeftInvNew(ndxDigitNewMax) = wCarry
uLeftInvPrev = uLeftInvCur : uLeftInvCur = New BigUInteger(awLeftInvNew)
End Sub
このコードを直接使用したい場合は、一部のコンストラクトに Visual Basic 2012 コンパイラが必要になる場合があります — 以前のバージョンは確認していません。また、最小の .Net バージョンも認識していません (少なくとも 3.5 で十分です)。コンパイルされたアプリケーションは、パフォーマンスは劣りますが、Mono で実行されることが知られています。私が絶対に確信している唯一のことは、VB から C# への自動トランスレーターを使用しようとするべきではないということです。自分の頭だけに頼ってください。