mm <mi*****@mustun .chwrote:
(Yes, I konw whats an object is...)
BTW. I did a translation of a pi callculation programm in C to Python.
(Do it by your own... ;-)
Calc PI for 800 digs(?). (german: Stellen)
int a=10000,b,c=280 0,d,e,f[2801],g;main(){for(; b-c;)f[b++]=a/5;
for(;d=0,g=c*2; c-=14,printf("%.4 d",e+d/a),e=d%a)for(b= c;d+=f[b]*a,
f[b]=d%--g,d/=g--,--b;d*=b);}
Below you'll find my translation. Note that I improved the algorithm
greatly. Note the nice easy to read algorithm also! This calculated
800 digits of pi in 0.1 seconds and 10,000 digits in 20 seconds.
------------------------------------------------------------
"""
Standalone Program to calculate PI using python only
Nick Craig-Wood <ni**@craig-wood.com>
"""
import sys
from time import time
class FixedPoint(obje ct):
"""A minimal immutable fixed point number class"""
__slots__ = ['value'] # __weakref__
digits = 25 # default number of digits
base = 10**digits
def __init__(self, value=0):
"""Initiali se the FixedPoint object from a numeric type"""
try:
self.value = long(value * self.base)
except (TypeError, ValueError), e:
raise TypeError("Can' t convert %r into long", value)
def set_digits(cls, digits):
"""Set the default number of digits for new FixedPoint numbers"""
cls.digits = digits
cls.base = 10**digits
set_digits = classmethod(set _digits)
def copy(self):
"Copy self into a new object"
new = FixedPoint.__ne w__(FixedPoint)
new.value = self.value
return new
__copy__ = __deepcopy__ = copy
def __add__(self, other):
"""Add self to other returning the result in a new object"""
new = self.copy()
new.value = self.value + other.value
return new
__radd__ = __add__
def __sub__(self, other):
"""Subtract self from other returning the result in a new object"""
new = self.copy()
new.value = self.value - other.value
return new
def __rsub__(self, other):
new = self.copy()
new.value = other.value - self.value
return new
def __mul__(self, other):
"""
Multiply self by other returning the result in a new object. The
number of digits is that of self.
Note that FixedPoint(x) * int(y) is much more efficient than
FixedPoint(x) * FixedPoint(y)
"""
new = self.copy()
if isinstance(othe r, (int, long)):
# Multiply by scalar
new.value = self.value * other
else:
new.value = (self.value * other.value) // other.base
return new
__rmul__ = __mul__
def __div__(self, other):
"""
Divide self by other returning the result in a new object. The
number of digits is that of self.
Note that FixedPoint(x) / int(y) is much more efficient than
FixedPoint(x) / FixedPoint(y)
"""
new = self.copy()
if isinstance(othe r, (int, long)):
# Divide by scalar
new.value = self.value // other
else:
new.value = (self.value * other.base) // other.value
return new
def __rdiv__(self, other):
if not isinstance(othe r, FixedPoint):
other = FixedPoint(othe r, self.digits)
return other.__div__(s elf)
def __str__(self):
"""
Convert self into a string. This will be the integral part of
the number possibly preceded by a - sign followed by a . then
exactly n digits where n is the number of digits specified on
creation.
"""
if self.value < 0:
s = str(-self.value)
else:
s = str(self.value)
s = s.zfill(self.di gits + 1)
s = s[:-self.digits] + "." + s[-self.digits:]
if self.value < 0:
s = "-" + s
return s
def __abs__(self):
"""Return the absolute value of self"""
new = self.copy()
if new.value < 0:
new.value = - new.value
return new
def __cmp__(self, other):
"""Compare self with other"""
return cmp(self.value, other.value)
def sqrt(n):
"""
Return the square root of n. It uses a second order
Newton-Raphson convgence. This doubles the number of significant
figures on each iteration. This will work for any finite
precision numeric type.
"""
x = n / 2 # FIXME find a better guess!
old_delta = None
while 1:
x_old = x
x = (x + n / x) / 2
delta = abs(x - x_old)
if old_delta is not None and delta >= old_delta:
break
old_delta = delta
return x
def pi_agm(one = 1.0, sqrt=sqrt):
"""
Brent-Salamin Arithmetic-Geometric Mean formula for pi. This
converges quadratically.
FIXME can increase the number of digits in each iteration to speed up?
"""
_1 = one
_2 = _1 + _1
a = _1
b = _1/sqrt(_2)
t = _1/2
k = 1
two_to_the_k = 2L
old_delta = None
while 1:
s = (a + b ) / 2
d = a - s
d = d * d
a = s
s = s * s
t = t - two_to_the_k * d
b = sqrt(s - d)
delta = abs(a - b)
# print k, delta, old_delta
if old_delta is not None and delta >= old_delta:
break
old_delta = delta
k = k + 1
two_to_the_k *= 2
a = a + b
return ( a * a ) / ( _2 * t)
if __name__ == "__main__":
try:
digits = int(sys.argv[1])
except:
digits = 100
print "Calculating",d igits,"digits of pi"
start = time()
FixedPoint.set_ digits(digits)
_1 = FixedPoint(1)
print pi_agm(_1, sqrt=sqrt)
dt = time() - start
print "That took",dt,"secon ds"
------------------------------------------------------------
But Python is much slower here then C here. I used a while-loop within a
while-loop. Not that much calculation here.
There is more than one way to skin this cat. A better algorithm helps
a lot.
If I really wanted lots of digits of pi from python I'd do it like
this. This is an example of the right tool for the job. 0.5ms looks
pretty good to me!
>>import math, gmpy
bits = int(800/math.log10(2))
start = time(); pi=gmpy.pi(bits ); dt = time()-start
print "That took",dt,"secon ds"
That took 0.0005519390106 2 seconds
>>pi
mpf('3.14159265 358979323846264 338327950288419 716939937510582 097494459230781 640628620899862 803482534211706 798214808651328 230664709384460 955058223172535 940812848111745 028410270193852 110555964462294 895493038196442 881097566593344 612847564823378 678316527120190 914564856692346 034861045432664 821339360726024 914127372458700 660631558817488 152092096282925 409171536436789 259036001133053 054882046652138 414695194151160 943305727036575 959195309218611 738193261179310 511854807446237 996274956735188 575272489122793 818301194912983 367336244065664 308602139494639 522473719070217 986094370277053 921717629317675 238467481846766 940513200056812 714526356082778 577134275778960 917363717872146 844090122495343 014654958537105 079227968925892 354201995611212 902196086403441 815981362977477 130996051870721 134999999837297 804995105973173 281609631859502 4459455e0',2657 )
>>>
--
Nick Craig-Wood <ni**@craig-wood.com--
http://www.craig-wood.com/nick