' Quote from
'Visual Basic 2005 Cookbook Solutions for VB 2005 Programmers
'by Tim Patrick (Author), John Craig (Author)
'# Publisher: O'Reilly Media, Inc. (September 21, 2006)
'# Language: English
'# ISBN-10: 0596101775
'# ISBN-13: 978-0596101770
Public Class Tester
Public Shared Sub Main
Console.WriteLine(FindPi(500))
End Sub
Private Shared NumberDigits As Integer
Public Shared Function FindPi(ByVal digits As Integer) As String
' ----- Calculate Pi to the specified number of digits,
' based on the formula:
' Pi/4 = arctan(1/2) + arctan(1/3)
Dim result As New System.Text.StringBuilder("PI=3.")
Dim digitIndex As Integer
Dim divFactor As Integer
' ----- Build an array that will hold manual calculations.
NumberDigits = digits + 2
Dim targetValue(NumberDigits) As Integer
Dim sourceValue(NumberDigits) As Integer
' ---- Perform the calculation.
divFactor = 2
ArcTangent(targetValue, sourceValue, divFactor)
divFactor = 3
ArcTangent(targetValue, sourceValue, divFactor)
ArrayMult(targetValue, 4)
' ----- Return a string version of the calculation.
For digitIndex = 1 To NumberDigits - 3
result.Append(Chr(targetValue(digitIndex) + Asc("0"c)))
Next digitIndex
Return result.ToString
End Function
Private Shared Sub ArrayMult(ByRef baseNumber() As Integer, _
ByRef multiplier As Integer)
' ----- Multiply an array number by another number by hand.
' The product remains in the array number.
Dim carry As Integer
Dim position As Integer
Dim holdDigit As Integer
' ----- Multiple each base digit, from right to left.
For position = NumberDigits To 0 Step -1
' ----- If the multiplication went past 9, carry the
' tens value to the next column.
holdDigit = (baseNumber(position) * multiplier) + carry
carry = holdDigit \ 10
baseNumber(position) = holdDigit Mod 10
Next position
End Sub
Private Shared Sub ArrayDivide(ByRef dividend() As Integer, ByRef divisor As Integer)
' ----- Divide an array number by another number by hand.
' The quotient remains in the array number.
Dim borrow As Integer
Dim position As Integer
Dim holdDigit As Integer
' ----- Process division for each digit.
For position = 0 To NumberDigits
' ----- If the division can't happen directly, borrow from
' the previous position.
holdDigit = dividend(position) + borrow * 10
dividend(position) = holdDigit \ divisor
borrow = holdDigit Mod divisor
Next position
End Sub
Private Shared Sub ArrayAdd(ByRef baseNumber() As Integer, ByRef addend() As Integer)
' ----- Add two array numbers together.
' The sum remains in the first array number.
Dim carry As Integer
Dim position As Integer
Dim holdDigit As Integer
' ----- Add each digit from right to left.
For position = NumberDigits To 0 Step -1
' ----- If the sum goes beyond 9, carry the tens
' value to the next column.
holdDigit = baseNumber(position) + addend(position) + carry
carry = holdDigit \ 10
baseNumber(position) = holdDigit Mod 10
Next position
End Sub
Private Shared Sub ArraySub(ByRef minuend() As Integer, ByRef subtrahend() As Integer)
' ----- Subtract one array number from another.
' The difference remains in the first array number.
Dim borrow As Integer
Dim position As Integer
Dim holdDigit As Integer
' ---- Subtract the digits from right to left.
For position = NumberDigits To 0 Step -1
' ----- If the subtraction would give a negative value
' for a column, we will have to borrow.
holdDigit = minuend(position) - subtrahend(position) + 10
borrow = holdDigit \ 10
minuend(position) = holdDigit Mod 10
If (borrow = 0) Then minuend(position - 1) -= 1
Next position
End Sub
Private Shared Function ArrayZero(ByRef baseNumber() As Integer) As Boolean
' ----- Report whether an array number is all zero.
Dim position As Integer
' ----- Examine each digit.
For position = 0 To NumberDigits
If (baseNumber(position) <> 0) Then
' ----- The number is nonzero.
Return False
End If
Next position
' ----- The number is zero.
Return True
End Function
Private Shared Sub ArcTangent(ByRef targetValue() As Integer, _
ByRef sourceValue() As Integer, _
ByVal divFactor As Integer)
' ----- Calculate an arctangent of a fraction, 1/divFactor.
' This routine performs a modified Maclaurin series to
' calculate the arctangent. The base formula is:
' arctan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9 - ...
' where -1 < x < 1 (it's 1/divFactor in this case).
Dim workingFactor As Integer
Dim incremental As Integer
' ----- Figure out the "x" part, 1/divFactor.
sourceValue(0) = 1
incremental = 1
workingFactor = divFactor
ArrayDivide(sourceValue, workingFactor)
' ----- Add "x" to the total.
ArrayAdd(targetValue, sourceValue)
Do
' ----- Perform the "- (xy)/y" part.
ArrayMult(sourceValue, incremental)
workingFactor = divFactor * divFactor
ArrayDivide(sourceValue, workingFactor)
incremental += 2
workingFactor = incremental
ArrayDivide(sourceValue, workingFactor)
ArraySub(targetValue, sourceValue)
' ----- Perform the "+ (xy)/y" part.
ArrayMult(sourceValue, incremental)
workingFactor = divFactor * divFactor
ArrayDivide(sourceValue, workingFactor)
incremental += 2
workingFactor = incremental
ArrayDivide(sourceValue, workingFactor)
ArrayAdd(targetValue, sourceValue)
Loop Until ArrayZero(sourceValue)
End Sub
End Class
|