用户:
红石小蝈查看:1 回复:2 评论:1 创建时间:2019-05-17T21:57:57
共计5个类,(1个成品,4个坑)咕咕咕
import turtle
from math import *
from turtle import Vec2D #This will stay here until I have a vec class
import fourier ###gonna be moved in###
####helpers function & constants####
def longer(a,b):
if len(a)>len(b):
return a
elif len(a)<len(b):
return b
else:
#print('same lenth')
return a,b
def n_to_s(x):
if float(x)>=0:
return '+'+str(x)
else :
return str(x)
def tp(p,pos_x,pos_y):
p.pu()
p.goto(float(pos_x), float(pos_y))
p.pd()
DEFAULT_COLOR='#66ccff'
AUTHERS_SPACE='https://space.bilibili.com/352143698'
DEFAULT_PEN=None
DRAW_WHEN_REPR=True
def do_drawing():
'''do this before u draw sth'''
global DEFAULT_PEN
DEFAULT_PEN=turtle.Turtle()
DEFAULT_PEN.speed(0)
if __name__=='__main__':
do_drawing()
####math constants####
M=2.302585092994046
number_types=['Rational','int','float']
func_types=['Po_func']
tri=[sin,cos,tan]
####math funcs & classes####
def Re(z):
'''return the real part of z'''
return z.real
def Im(z):
'''return the imaginary part of z'''
return z.imag
def Arg(z):
'''return the principle argument '主幅角'
of a complex number'''
return atan2(Im(z),Re(z))
def vec(z):return Vec2D(Re(z),Im(z))
def cot(theta):
'''return the cotangent of theta'''
return tan(theta-pi/2)
class Rational:
'''a rational number class instead of
python integer or floating numbers, the
base of rational functions'''
def __init__(self,num=0,den=1):
if den == 0:
raise ZeroDivisionError('the denominator can\'t be zero')
elif not isinstance(num,(int,float)) and isinstance(den,(int,float)):
raise TypeError('the numrator and the denominator can only be numbers')
if den == 1 and isinstance(num,float):
raise NotImplementedError('''you still can't change floating numbers into
Rationals,if u have questions please go to'''+AUTHERS_SPACE+'for help')
else:
self.num=num
self.den=den
def reduct(self):
'''make the fraction in the lowest term'''
num=int(self.num/gcd(self.num,self.den))
den=int(self.den/gcd(self.num,self.den))
self.num=num
self.den=den
##change rationals into integers and floating numbers
def __int__(self):
return self.num//self.den
def __float__(self):
return self.num/self.den
##comparing rationals with others numbers
def __eq__(self,other):
return float(self)==float(other)
def __ge__(self,other):
return float(self)>=float(other)
def __gt__(self,other):
return float(self)>float(other)
def __le__(self,other):
return float(self)<=float(other)
def __lt__(self,other):
return float(self)<float(other)
def __ne__(self,other):
return float(self)!=float(other)
##compute rationals with numbers
def __add__(self,other):
if isinstance(other,(int,Po_func)):
return Rational(self.num+other*self.den,self.den)
elif isinstance(other,Rational) :
d=self.den*other.den
n=self.den*other.num+self.num*other.den
a=Rational(d,n)
a.reduct()
return a
def __neg__(self):
return Rational(-self.num,self.den)
def __sub__(self,other):
return self+(-other)
def __rsub__(self,other):
return -(self-other)
def __mul__(self,other):
if isinstance(other,int):
a=Rational(self.num*other,self.den)
a.reduct()
return a
elif isinstance(other,Rational):
a=Rational(self.num*other.num,self.den*other.den)
a.reduct()
return a
def __div__(self,other):
if float(other)==0:
raise ZeroDivisionError('Can\'t divide by zero')
if isinstance(other,int):
a = Rational(self.num,self.den*other)
a.reduct()
return a
elif isinstance(other,Rational) :
a = Rational(self.num*other.den,self.den*other.num)
a.reduct()
return a
def __rdiv__(self,other):
if self==0:
raise ZeroDivisionError('Can\'t divide by zero')
a = Rational(self.den*other,self.num)
a.reduct()
return a
def __pow__(self,other):
if other>=0:
return Rational(self.num**other,self.den**other)
if other<0:
return Rational(self.den**(-other),self.num**(-other))
__rmul__=__mul__
__radd__=__add__
##show rationals
def __repr__(self):
if self.den==1:
return str(self.num)
return '('+str(self.num)+'/'+str(self.den)+')'
class Interval:
'''mathmatical single interval class
in python, base of lots of things
e.g.:(i0,i1 are two intervals)
i0+i1 : i0∪i1
i0.contain(i1) : i1⊆i0
i0.include(num) : num∈i0
'''
def __init__(self,l_bound=-inf,r_bound=inf,l_open=True,r_open=True):
if (isinstance(l_bound,(int,float,Rational))
and isinstance(r_bound,(int,float,Rational))):
if r_bound<l_bound :
r_bound=l_bound
if not(l_open or r_open):
l_open=r_open=False
self.l_bound=l_bound
self.r_bound=r_bound
self.l_open=l_open
self.r_open=r_open
#elif isinstance(l_bound,str):self=Interval.fromstr(l_bound)
else:
raise TypeError('the bounds can only be numbers')
@clas喵ethod
def fromstr(cls,i):
if not isinstance(i,str):
raise TypeError
l_open= i[0]=='('
r_open= i[-1]==')'
a,b = i[1:-1].split(',')
l_bound=float(a)
r_bound=float(b)
i=cls(l_bound,r_bound,l_open,r_open)
return i
###compare Intervals
def __eq__(self, other):
return ((self.l_bound==other.l_bound and self.r_bound==other.r_bound)
and (self.l_open==other.l_open and self.r_open==other.r_open))
def __ge__(self, other):
if self.r_open and (not other.r_open):return self.r_bound>other.r_bound
else:return self.r_bound>=other.r_bound
def __gt__(self, other):
if (not self.r_open) and other.r_open:return self.r_bound>=other.r_bound
else:return self.r_bound>other.r_bound
def __le__(self, other):
if self.l_open and (not other.l_open):return self.l_bound<other.l_bound
else:return self.l_bound<=other.l_bound
def __lt__(self, other):
if (not self.l_open) and other.r_open:return self.r_bound>=other.r_bound
else:return self.r_bound>other.r_bound
def __ne__(self, other):
return not self==other
###computing Intervals
def __add__(self,other):
if isinstance(other,Interval):
if self>other:_x,_y=self,other
else:_x,_y=other,self
if _x.l_open and _y.r_open:_b= _x.l_bound<_y.r_bound
else: _b= _x.l_bound<=_y.r_bound
if _b:
if _x.l_bound<_y.l_bound:return _x
else:return Interval(_y.l_bound,_x.r_bound,_y.l_open,_x.r_open)
else:return Compound_Interval(_x,_y)
elif isinstance(other,Compound_Interval):
inters=[self]
for _x in other.intervals:
if self.include(_x):#_r = self+_x
pass
elif _x.include(self):
return other
elif isinstance(_x+self,Interval):
inters.append(_x+self)
else:
inters.append(_x)
return Compound_Interval.fromlist(inters)
#raise NotImplementedError
else:
raise TypeError('you can only add intervals to intervals')
###main methods of Intervals
def include(self,num):
'''return True if num∈interval
return False otherwise'''
if self.l_open :b = self.l_bound<num
else :b = self.l_bound<=num
if self.r_open:b = b and num<self.r_bound
else:b = b and num<=self.r_bound
return b
def contain(self, other):
'''return True if other⊆self
return False otherwise
'''
if self.l_open and (not other.l_open):b = self.l_bound<other.l_bound
else :b = self.l_bound<=other.l_bound
if self.r_open and (not other.r_open):b = b and other.r_bound<self.r_bound
else :b = b and other.r_bound<=self.r_bound
return b
##represent method
def __repr__(self):
s=''
if self.l_open :s+='('
else :s+='['
s+=str(self.l_bound)+','+str(self.r_bound)
if self.r_open:s+=')'
else:s+=']'
return s
__radd__=__add__
Intvl = Interval
str_to_intvl = Intvl.fromstr
R = Interval()
class Compound_Interval:
'''the union set of single intervals,
base of things
'''
def __init__(self,*s):
s=list(s)
s.sort(reverse=True)
self.intervals=s
@clas喵ethod
def fromlist(cls,l):
if isinstance(l,list):
i=cls()
l.sort(reverse=True)
i.intervals=l
return i
else:
raise TypeError
def simplify(self):
'''simplify the set,not implemented'''
#for _x in self.intervals:
raise NotImplementedError('don\'t ask why, I\'m just too lazy')
def __repr__(self):
s=''
for x in self.intervals:
s+=str(x)+'∪'
return s[:-1]
class Sequence:
'''get a mathmatic sequence
with a function and a name'''
def __init__(self,func,name,args=None,lenth=256):
self.f=func
self.l=[]
self.args=args
self.name=name
self.len=lenth
def get(self):
for x in range(self.len):
self.l.append(self.f(x,self.args))
def serie(self,lenth=None,infin=True):
if self.l==[]:
self.get()
if lenth==None:
lenth=len(self.l)
if infin and self.l[-1]>=self.l[0]:
return inf
return sum(self.l)
def __getitem__(self,i):
if self.l==[]:
return self.f(i)
else:
return self.l[i]
def __repr__(self):
return '{'+self.name+'_n}'
def _Arith(n,a_0=0,d=None):
if isinstance(a_0,tuple) :
a_0,d=a_0
return a_0+n*d
def _Geo(n,a_0=1,p=None):
if isinstance(a_0,tuple) :
a_0,p=a_0
return a_0*(p**n)
Arithmetic=Sequence(_Arith,'a',(0,2))
Geometric=Sequence(_Geo,'a',(1,0.5))
class Po_func:
'''get a polynomial function
instead of a python function;
put a list of coefficient
at coes'''
def __init__(self, coes=[0],name='f',indep_var_name='x'):
self.name=name
self.indep_var_name=indep_var_name
self.full_name=name+'('+indep_var_name+')'
while coes[-1]==0 and len(coes)>1:
coes.pop()
self.coes=coes
self.pow=len(coes)-1
def __call__(self,x):
y=0
for n in range(len(self.coes)):
y+=self.coes[n]*(x**n)
return y
def __add__(self,other):
if isinstance(other,(int,float,Rational)):
other = Po_func([other])
p=len(self.coes)
q=len(other.coes)
new_coes=[]
for x in range(max(p,q)):
if x<min(p,q):
new_coes.append(self.coes[x]+other.coes[x])
else:
new_coes.append(longer(self.coes,other.coes)[x])
return Po_func(new_coes,'h')
def __neg__(self):
n_c=[]
for _x in self.coes:
n_c.append(-_x)
return Po_func(n_c,'-f')
def __sub__(self,other):
return self+(-other)
def __rsub__(self,other):
return -self+other
def __str__(self):
s=n_to_s(self.coes[0])
for n in range(1,self.pow+1):
a=self.coes[n]
if a!=0:
s=n_to_s(a)+ self.indep_var_name+'^'+str(n)+s
return s
def __repr__(self):
if DRAW_WHEN_REPR:draw_func(self)
return self.full_name+'='+str(self)
def __mul__(self,other):
if isinstance(other,(Rational,int,float)) :
new_coes=[]
for x in range(self.pow+1):
new_coes.append(self.coes[x]*other)
return Po_func(new_coes)
elif isinstance(other,Po_func):
new_func=Po_func()
for _x in range(other.pow+1):
a=(self*other.coes[_x])._higher(_x)
new_func+=a
return new_func
else :
raise TypeError('Polynomial function can only be multiplied with nums or funcs')
def __divmod__(self,other):
if not isinstance(other,Po_func):
raise TypeError('not available')
f = self
g = other
new_coes=[]
while f.pow>=g.pow:
a=(f.coes[-1]/g.coes[-1])
new_coes.insert(0,a)
f-=g._higher(f.pow-g.pow)*a
#print(f,g)
return (Po_func(new_coes,'p'),f)
def __pow__(self,other):
if isinstance(other,int) and other>=0:
new_func=Po_func([1])
for _x in range(other):
new_func*=self
return new_func
##elif not ...:
## pass
else :
raise TypeError('''at present, Po_funcs can only be raised to a integer greater than Zero
if u have more questions please go to'''+AUTHERS_SPACE+'for further information')
def _higher(self,a):
'''the basic mathod of multiplying x**a'''
return Po_func([0]*a+self.coes)
def deriv(self):
'''return the derivative of the function
no agruments'''
new_coes=[]
for _x in range(1,self.pow+1):
new_coes.append(_x*self.coes[_x])
return Po_func(new_coes,self.name+"'")
__rmul__=__mul__
__radd__=__add__
x=Po_func([0,1],name='')
class Ra_func(Rational):
'''rational functions instead of
python functions,den and num must
be both polynomial functions
'''
def __init__(self,num=Po_func([0]),den=Po_func([1])):
if isinstance(num,Po_func) and isinstance(den,Po_func):
self.num=num
self.den=den
else :
raise TypeError('den and num must be both polynomial functions')
def __call__(self,x):
if self.den(x) != 0:
return self.num(x)/self.den(x)
elif self.num(x) != 0:
return inf
else :
return nan
def hail_conjecture(x):
if x>0 and int(x)==x:
tm=0
while x!=1:
if x%2==0:
x=x/2
else:
x=3*x+1
喵=喵+1
#print(喵)
return 2**(喵-30)
else:
raise ArithmeticError('x can only be an integer bigger than zero')
### drawing functions ###
def coor_system(size=20,color=DEFAULT_COLOR):
x_pen=turtle.Turtle()
x_pen.color(color)
x_pen.speed(0)
y_pen=turtle.Turtle()
y_pen.color(color)
x_pen.speed(0)
tp(x_pen,-400,0)
tp(y_pen,0,-400)
y_pen.lt(90)
for num in range(-400,401,size):
x_pen.write(num//size)
x_pen.fd(size)
y_pen.write(num//size)
y_pen.fd(size)
del x_pen,y_pen
def draw_func(f,delta=Rational(1,10),size=20,line=0,p=None,color=DEFAULT_COLOR,r=False):
'''draw the graph of a function'''
if p==None:
if not isinstance(DEFAULT_PEN,turtle.Turtle):
do_drawing()
p=DEFAULT_PEN
p.color(color)
if r:
tp(p,0,f(Rational()))
_x=Rational()
else:
tp(p,0,f(0))
_x=0
delta=float(delta)
while float(_x)<=400/size:
if line==0:p.goto(float(_x*size),float(f(_x))*size)
else:
tp(p,float(_x*size),float(f(_x))*size)
p.dot(line)
_x+=delta
if r:
tp(p,0,f(Rational()))
_x=Rational()
else:
tp(p,0,f(0))
_x=0
while float(_x)>=-400/size:
if line==0:p.goto(float(_x*size),float(f(_x))*size)
else:
tp(p,float(_x*size),float(f(_x))*size)
p.dot(line)
_x-=delta
### testing ###
if __name__=='__main__':
def w0(x):
if 0<x<=pi : return sqrt(x*(pi-x))
elif pi<x<=tau:return -sqrt((x-pi)*(2*pi-x))
else :return 0
coor_system()
_a=input('draw a function (0~3)')
if _a=='0':
draw_func(sin,color='#00ffcc')
draw_func(cos,color='#ffb1c0')
elif _a=='1':
DEFAULT_PEN.ht()
draw_func(hail_conjecture,1,0.1,1.5,color='#39c5bb')
elif _a=='2':
_b=input('compare?(T for true)')
colors=['#ffb1c0','#ffff00','#00ffcc','#66ccff','#0080ff','#39c5bb','#ee0000']
bn=[]
for n in range(18):
bn.append(fourier.series(n,False,w0))
for n in range(1,8):
if _b != 'T':DEFAULT_PEN.reset()
def w(x):return fourier.wave(x,2*n,b=bn)
draw_func(w,0.02,50,color=colors[n-1])
elif _a=='3':
bn=[]
for q in range(200):
bn.append(fourier.series(q,False,w0))
def w(x):return fourier.wave(x,200,b=bn)
draw_func(w,0.01,50)
elif _a=='4':
pass