roots 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/roots.rb +166 -0
- 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:
|