roots 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/roots.rb +166 -0
  2. metadata +48 -0
data/lib/roots.rb ADDED
@@ -0,0 +1,166 @@
1
+ =begin
2
+ Author: Jabari Zakiya, Original: 2009-12-25
3
+ Revision-2: 2009-12-31
4
+ Revision-3: 2010-6-2
5
+ Revision-4: 2010-12-15
6
+
7
+ Module 'Roots' provides two methods 'root' and 'roots'
8
+ which will find all the nth roots of real and complex
9
+ numerical values.
10
+
11
+ ---------------
12
+ Install process:
13
+ Place module file 'roots.rb' into 'lib' directory of ruby
14
+ version. Then from irb session, or a source code file, do:
15
+
16
+ require 'roots'
17
+ #For extended math features also do: require 'mathn'
18
+ #Mixin 'Roots' into class Numeric
19
+ Rev-4 Add line 'class Numeric; include Roots end'
20
+ to end of file to automatically add root/s methods in
21
+ all class Numeric types.
22
+ ---------------
23
+
24
+ Use syntax: val.root(n,{k})
25
+ root(n,k=0) n is root 1/n exponent, integer > 0
26
+ k is nth ccw root 1..n , integer >=0
27
+ If k not given default root returned, which are:
28
+ for +val => real root |val**(1.0/n)|
29
+ for -val => real root -|val**(1.0/n)| when n is odd
30
+ for -val => first ccw complex root when n is even
31
+
32
+ 9.root(2); -32.root(5,3), -100.43.root 6,6
33
+
34
+ Use syntax: val.roots(n,{opt})
35
+ roots(n,opt=0) n is root 1/n exponent, integer > 0
36
+ opt, optional string input, are:
37
+ 0 : default (no input), return array of n ccw roots
38
+ 'c'|'C': complex, return array of complex roots
39
+ 'e'|'E': even, return array even numbered roots
40
+ 'o'|'O': odd , return array odd numbered roots
41
+ 'i'|'I': imag, return array of imaginary roots
42
+ 'r'|'R': real, return array of real roots
43
+ An empty array is returned for an opt with no members.
44
+
45
+ 9348134943.roots(9); -89.roots(4,'real'); 2.2.roots 3,'Im'
46
+
47
+ Can ask: How many real roots of x: x.roots(n,'real').size
48
+ What's the 3rd 5th root of (4+9i): Complex(4,9).root(5,3)
49
+
50
+ ---------------
51
+ Mathematical foundations
52
+
53
+ 1) i = (-1)^(1/2)
54
+ 2) i^1 = i
55
+ 3) i^2 = -1
56
+ 4) i^3 = -i
57
+ 5) i^4 = 1
58
+ 6) Then it repeats, e.g.: i^5 = i*(i^4) = i
59
+ 7) e^(i*x) = cos(x) + i*sin(x)
60
+ 8) when x = PI/2 then e^(PI*i/2) = i
61
+
62
+ For roots (-a)^(1/n) of negative real values:
63
+
64
+ x = |a^(1/n)|*(-1)^(1/n)
65
+ from 2) above
66
+ x = |a^(1/n)|*(i^2)^(1/n)
67
+ x = |a^(1/n)|*(i)^(2/n)
68
+ apply 8) from above
69
+ x = |a^{1/n)|*e^(PI*i/2)^(2/n)
70
+ x = |a^(1/n)|*e^(PI*i/n)
71
+ 9) x = |a^(1/n)|*(cos(PI/n) + i*sin(PI/n))
72
+
73
+ For roots (a)^(1/n) of positive real values:
74
+
75
+ x = (a)^(1/n)
76
+ x = (a*1)^(1/n)
77
+ x = |a^(1/n)|*(1)^(1/n)
78
+ from 5) above
79
+ x = |a^(1/n)|*(i^4))^(1/n)
80
+ x = |a^(1/n)|*(i)^(4/n)
81
+ apply 8) from above
82
+ x = |a^{1/n)|*e^(PI*i/2)^(4/n)
83
+ x = |a^(1/n)|*e^(2*PI*i/n)
84
+ 10) x = |a^(1/n)|*(cos(2*PI/n) + i*sin(2*PI/n))
85
+
86
+ There are n distinct roots (values):
87
+ ---------------
88
+
89
+ Ruby currently gives incorrect values for x|y axis angles
90
+ cos PI/2 => 6.12303176911189e-17
91
+ sin PI => 1.22460635382238e-16
92
+ cos 3*PI/2 => -1.83690953073357e-16
93
+ sin 2*PI => -2.44921970764475e-16
94
+
95
+ These all should be 0.0, which causes incorrect root values there.
96
+ I 'fix' these errors by clipping absolute values less than a value
97
+ I call TRIG-EPSILON so they produces the correct results.
98
+
99
+ Extract this code into separate file and 'require' into your apps
100
+ to get correct|exact results for x|y axis angles and still get same
101
+ accuracy for extremely small delta angles to the x|y axis.
102
+ cosine(89.9999999999*PI/180) => 1.74534333112399e-11
103
+ cosine(90.0*PI/180) => 0.0
104
+ cosine(90.0000000001*PI/180) => -1.74543140899798e-12
105
+ =end
106
+
107
+ # file roots.rb
108
+
109
+ module Roots
110
+ require 'complex'
111
+ include Math
112
+
113
+ def root(n,k=0) # return nth root k=1..n;, or default for k=0
114
+ raise "Root n not an integer > 0" unless n.kind_of?(Integer) && n>0
115
+ raise "Index k not an integer >= 0" unless k.kind_of?(Integer) && k>=0
116
+ return self if n == 1 || self == 0
117
+ mag = abs**n**-1
118
+ return rootn(mag,arg/n,k>0 ? k-1:0,n) if kind_of?(Complex)
119
+ return rootn(mag,PI/n,k-1) if k>0 # nth root any real
120
+ return mag if self > 0 # pos real default
121
+ return -mag if n&1 == 1 # neg real default, n odd
122
+ return rootn(mag,PI/n) # neg real default, n even
123
+ end
124
+
125
+ def roots(n,opt=0) # returns array of roots, [] option not valid
126
+ raise "Root n not an integer > 0" unless n.kind_of?(Integer) && n>0
127
+ raise "Invalid option" unless opt == 0 || opt =~ /^(c|e|i|o|r|C|E|I|O|R)/
128
+ return [self] if n == 1 || self == 0
129
+ mag = abs**n**-1
130
+ theta = kind_of?(Complex) ? arg/n : PI/n
131
+ roots = []
132
+ case opt
133
+ when /^(o|O)/ # odd roots 1,3,5...
134
+ 0.step(n-1,2) {|k| roots << rootn(mag,theta,k,n)}
135
+ when /^(e|E)/ # even roots 2,4,6...
136
+ 1.step(n-1,2) {|k| roots << rootn(mag,theta,k,n)}
137
+ when /^(r|R)/ # real roots Complex(x,0) = (x+i0)
138
+ n.times {|k|
139
+ x=rootn(mag,theta,k,n); roots << x if x.imag == 0}
140
+ when /^(i|I)/ # imaginry roots Complex(0,y) = (0+iy)
141
+ n.times {|k|
142
+ x=rootn(mag,theta,k,n); roots << x if x.real == 0}
143
+ when /^(c|C)/ # complex roots Complex(x,y) = (x+iy)
144
+ n.times {|k|
145
+ x=rootn(mag,theta,k,n); roots << x unless
146
+ x.imag == 0 || x.real == 0}
147
+ else # all n roots
148
+ n.times {|k| roots << rootn(mag,theta,k,n)}
149
+ end
150
+ return roots
151
+ end
152
+
153
+ private # don't show as methods in mixin class
154
+ TRIG_EPSILON = 2.5e-16
155
+ def sine(x); y=sin(x); y.abs < TRIG_EPSILON ? 0.0:y end
156
+ def cosine(x); y=cos(x); y.abs < TRIG_EPSILON ? 0.0:y end
157
+ def tangent(x); sine(x)/cosine(x) end # more accurate tan
158
+
159
+ def rootn(mag,theta,k=0,n=1) # nth root of a real|complex
160
+ angle_n = kind_of?(Complex) ? theta+(2*k*PI)/n :
161
+ self > 0 ? 2*(k+1)*theta : (2*k+1)*theta
162
+ mag*Complex(cosine(angle_n),sine(angle_n))
163
+ end
164
+ end
165
+
166
+ class Numeric; include Roots end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: roots
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jabari Zakiya
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-27 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! 'For val (real/complex) and root n: val.root(n,[1-n]) and val.roots(n,
15
+ [opt]) '
16
+ email:
17
+ - jzakiya@gmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/roots.rb
23
+ homepage: http://www.scribd.com/doc/60067570/Roots-in-Ruby
24
+ licenses: []
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.24
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: two methods 'root' and 'roots' to compute all n roots of real/complex numbers
47
+ test_files: []
48
+ has_rdoc: