BigNumbers in IronPython QuickStart Sample
Illustrates the basic use of the arbitrary precision classes: BigInteger, BigRational, BigFloat in IronPython.
View this sample in: C# Visual Basic F#
```Python import numerics from math import log # The arbitrary precision types reside in the Extreme.Mathematics # namespace. from Extreme.Mathematics import * # Illustrates the use of the arbitrary precision number # classes in Numerics.NET. # In this QuickStart sample, we'll use 5 different methods to compute # the value of pi, the ratio of the circumference to the diameter of # a circle. # The number of decimal digits. digits = 10000 # The equivalent number of binary digits, to account for round-off error: binaryDigits = (int)(8 + digits * log(10, 2)) # The number of digits in the last correction, if applicable. # correctionDigits # First, create an AccuracyGoal for the number of digits we want. # We'll add 5 extra digits to account for round-off error. goal = AccuracyGoal.Absolute(digits + 5) print "Calculating {0} digits of pi:".format(digits) # Create a stopwatch so we can time the results. from System.Diagnostics import Stopwatch sw = Stopwatch() # # Method 1: Arctan formula # # pi/4 = 88L(172) + 51L(239) + 32L(682) + 44L(5357) + 68L(12943) # Where L(p) = Arctan(1/p) # We will use big integer arithmetic for this. # Helper function to compute Arctan(1/p) # <param name="p">The reciprocal of the argument.</param> # <param name="binaryDigits">The number of binary digits in the result.</param> # <returns>Arctan(1/<paramref name="p"/>) to <paramref name="binaryDigits"/> binary digits.</returns> def Arctan(p, binaryDigits): # We scale the result by a factor of 2^binaryDigits. # The first term is 1/p. power = BigInteger.Pow(2, binaryDigits) / p # We store the sum in result. result = power subtract = True k = 0 while not power.IsZero: k = k + 1 # Expressions involving big integers look exactly like any other arithmetic expression: # The kth term is (-1)^k 1/(2k+1) 1/p^2k. # So the power is 1/p^2 times the previous power. power /= p ** 2 # And we alternately add and subtract if subtract: result -= power / (2 * k + 1) else: result += power / (2 * k + 1) subtract = not subtract # Scale the result. return BigFloat.ScaleByPowerOfTwo(BigFloat(result), -binaryDigits) print "Arctan formula using integer arithmetic:" sw.Start() coefficients = [ 88, 51, 32, 44, 68 ] arguments = [ 172, 239, 682, 5357, 12943 ] pi = BigFloat.Zero for k in range(0, 5): pi += coefficients[k] * Arctan(arguments[k], binaryDigits) print "Step {0}: ({1:.3f} seconds)".format(k + 1, sw.Elapsed.TotalSeconds) # The ScaleByPowerOfTwo is the fastest way to multiply # or divide by a power of two: pi = BigFloat.ScaleByPowerOfTwo(pi, 2) sw.Stop() print "Total time: {0:.3f} seconds.".format(sw.Elapsed.TotalSeconds, pi) print # # Method 2: Rational approximation # # pi/2 = 1 + 1/3 + (1*2)/(3*5) + (1*2*3)/(3*5*7) + ... # = 1 + 1/3 * (1 + 2/5 * (1 + 3/7 * (1 + ...))) # We gain 1 bit per iteration, so we know where to start. print "Rational approximation using rational arithmetic." print "This is very inefficient, so we only do up to 10000 digits." sw.Start() an = BigRational.Zero n0 = binaryDigits if digits <= 10000 else (int)(8 + 10000 * log(10, 2)) for n in range(n0,0,-1): an = BigRational(n, 2 * n + 1) * an + 1 pi = BigFloat(2 * an, goal, RoundingMode.TowardsNearest) sw.Stop() print "Total time: {0:.3f} seconds.".format(sw.Elapsed.TotalSeconds, pi) print # # Method 3: Arithmetic-Geometric mean # # By Salamin & Brent, based on discoveries by C.F.Gauss. # See http:#www.cs.miami.edu/~burt/manuscripts/gaussagm/agmagain-hyperref.pdf print "Arithmetic-Geometric Mean:" sw.Reset() sw.Start() x1 = BigFloat.Sqrt(2, goal, RoundingMode.TowardsNearest) x2 = BigFloat.One S = BigFloat.Zero c = BigFloat.One for k in xrange(0, int.MaxValue): S += BigFloat.ScaleByPowerOfTwo(c, k - 1) aMean = BigFloat.ScaleByPowerOfTwo(x1 + x2, -1) gMean = BigFloat.Sqrt(x1 * x2) x1 = aMean x2 = gMean c = (x1 + x2) * (x1 - x2) # GetDecimalDigits returns the approximate number of digits in a number. # A negative return value means the number is less than 1. correctionDigits = -c.GetDecimalDigits() print "Iteration {0}: {1:F1} digits ({2:.3f} seconds)".format(k, correctionDigits, sw.Elapsed.TotalSeconds) if correctionDigits >= digits: break pi = x1 * x1 / (1 - S) sw.Stop() print "Total time: {0:.3f} seconds.".format(sw.Elapsed.TotalSeconds, pi) print # # Method 4: Borweins' quartic formula # # This algorithm quadruples the number of correct digits # in each iteration. # See http:#en.wikipedia.org/wiki/Borwein's_algorithm print "Quartic formula:" sw.Reset() sw.Start() sqrt2 = BigFloat.Sqrt(2, goal, RoundingMode.TowardsNearest) y = sqrt2 - BigFloat.One a = BigFloat(6, goal) - BigFloat.ScaleByPowerOfTwo(sqrt2, 2) y2 = y * y y4 = y2 * y2 correctionDigits = 0 k=1 while 4 * correctionDigits < digits: qrt = BigFloat.Root(1 - y4, 4) y = BigFloat.Subtract(1, qrt, goal, RoundingMode.TowardsNearest) \ / BigFloat.Add(1, qrt, goal, RoundingMode.TowardsNearest) # y = BigFloat.Divide(1 - qrt, 1 + qrt, AccuracyGoal.InheritAbsolute, RoundingMode.TowardsNearest) y2 = y * y y3 = y * y2 y4 = y2 * y2 da = (BigFloat.ScaleByPowerOfTwo(y + y3, 2) + (6 * y2 + y4)) * a \ - BigFloat.ScaleByPowerOfTwo(y + y2 + y3, 2 * k + 1) da = da.RestrictPrecision(goal, RoundingMode.TowardsNearest) a += da correctionDigits = -da.GetDecimalDigits() print "Iteration {0}: {1:F1} digits ({2:.3f} seconds)".format(k, correctionDigits, sw.Elapsed.TotalSeconds) k = k+1 pi = BigFloat.Inverse(a) sw.Stop() print "Total time: {0:.3f} seconds.".format(sw.Elapsed.TotalSeconds, pi) print # # Method 5: The built-in method # # The method used to compute pi internally is an order of magnitude # faster than any of the above. print "Built-in function:" sw.Reset() sw.Start() pi = BigFloat.GetPi(goal) sw.Stop() print "Total time: {0:.3f} seconds.".format(sw.Elapsed.TotalSeconds, pi) # The highest precision value of pi is cached, so # getting pi to any precision up to that is super fast. print "Built-in function (cached):" sw.Reset() sw.Start() pi = BigFloat.GetPi(goal) sw.Stop() print "Total time: {0:.3f} seconds.".format(sw.Elapsed.TotalSeconds, pi) ```