#-------------------------------------------------- # Extended mathematical routines #-------------------------------------------------- require 'complex' # Find prime factors of a number def factorize(inum, switch=0) if inum < 0 then num=-inum else num=inum end primes = [] for i in 2 .. num primes[i] = i end # generate table of primes using Eratosthenes' Sieve for i in 2 .. Math.sqrt(num) next unless primes[i] (i*i).step(num, i) do |j| primes[j] = nil end end # remove nils primes = primes.compact # find prime factors x = [] for k in 0..primes.size-1 u = num while u % primes[k] == 0 u = u/primes[k] x << primes[k] end end # convert array of factors to a string y = "" x.each{|i| y=y+"x"+i.to_s} y = y[1..y.size] #return array or string form if switch == 0 then return x else return y end end #factorize # Cancel out matching items from two lists def cancel(list1, list2) # what items are present? items=(list1+list2).uniq its1={}; its2={} items.each{|i| its1[i] = 0} items.each{|i| its2[i] = 0} # count items list1.each{|i| its1[i]+=1} list2.each{|i| its2[i]+=1} # cancel matching items items.each do |i| if its1[i]>its2[i] then its1[i]-=its2[i]; its2[i]=0 else its2[i]-=its1[i]; its1[i]=0 end end # rebuild cancelled lists clist1=[]; clist2=[] items.each{|i| its1[i].times{clist1 << i}} items.each{|i| its2[i].times{clist2 << i}} return clist1, clist2 end # simplify a fraction def simplify(num,denom) x = factorize(num,0) y = factorize(denom,0) z = cancel(x,y) snum = 1; sdenom = 1; z[0].each{|i| snum*=i} z[1].each{|i| sdenom*=i} if (num<0).^(denom<0) then return -snum, sdenom elsif num==0 return 0, sdenom else return snum, sdenom end end # Highest Common Factor of integers via factorisation def hcff(a,b) c=simplify(a,b)[0] if c==0 then 0 else a/c end end # Highest Common Factor using Euclid's algorithm def hcf(a, b) if b == 0 then return a else return gcd(b, a % b) end end # Greatest Common Divisor for integers or complex def gcd(a,b) if (a.class==Complex) or (b.class==Complex) then x=hcf(a.real,b.real) y=hcf(a.image,b.image) Complex(x,y) else hcf(a,b) end end # Reduce a fraction, integer or complex def reduce(a,b) c=gcd(a,b) if c==0 then return [a,b] else return [a/c, b/c] end end # Least Common Multiple def lcm(a,b) (a*b)/hcf(a,b) end #--------------------------------------------------------------------------- # Square root of pos and neg numbers -> Complex #--------------------------------------------------------------------------- def csqrt(a) if a < 0 then return Complex(0,Math.sqrt(-a)) else return Complex(Math.sqrt(a),0) end end #------------------------------------------------------------------------------ # Extend Ruby number classes for better print formatting #------------------------------------------------------------------------------ # Default number print format \$format = "%g" # Abbreviations for creating complex and rational literals def c(r,i) Complex(r,i) end def r(n,d) Rational(n,d) end #------------------------------------------------------------------------------------------------------------- # Smarter to_s methods for number classes Complex, Fixnum, Float and Rational #------------------------------------------------------------------------------------------------------------- class Complex def to_f Complex(@real.to_f, @image.to_f) end def to_s(f=\$format) s="" s=s+(sprintf f,@real) unless @real == 0 s=s+"+" unless @image <= 0 or @real == 0 s=s+(sprintf f,@image) unless @image == 0 or @image.abs == 1 s=s+"-" if @image == -1 s=s+"i" unless @image == 0 if s=="" then return "0" else return s end end end class Fixnum def to_s(f=\$format) sprintf f,self.real end end class Float def to_s(f=\$format) sprintf f,self.real end end class Rational def to_s(f=\$format) (sprintf f,self.numerator)+"/"+(sprintf f,self.denominator) end end