Skip to content

Instantly share code, notes, and snippets.

@jzakiya
Created June 2, 2010 16:33
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jzakiya/422636 to your computer and use it in GitHub Desktop.
Save jzakiya/422636 to your computer and use it in GitHub Desktop.
=begin
Author: Jabari Zakiya, Original: 2009-12-25
Revision-2: 2009-12-31
Revision-3: 2010-6-2
Revision-4: 2010-12-15
Revision-5: 2011-5-11
Revision-6: 2011-5-15
Module 'Roots' provides two methods 'root' and 'roots'
which will find all the nth roots of real and complex
numerical values.
---------------
Install process:
Place module file 'roots.rb' into 'lib' directory of ruby
version. Then from irb session, or a source code file, do:
require 'roots'
or
require '/path_to/roots.rb'
---------------
Use syntax: val.root(n,{k})
root(n,k=0) n is root 1/n exponent, integer > 0
k is nth ccw root 1..n , integer >=0
If k not given default root returned, which are:
for +val => real root |val**(1.0/n)|
for -val => real root -|val**(1.0/n)| when n is odd
for -val => first ccw complex root when n is even
9.root(2); -32.root(5,3); (-100.43).root 6,6
Use syntax: val.roots(n,{opt})
roots(n,opt=0) n is root 1/n exponent, integer > 0
opt, optional string input, are:
0 : default (no input), return array of n ccw roots
'c'|'C': complex, return array of complex roots
'e'|'E': even, return array even numbered roots
'o'|'O': odd , return array odd numbered roots
'i'|'I': imag, return array of imaginary roots
'r'|'R': real, return array of real roots
An empty array is returned for an opt with no members.
9348134943.roots(9); -89.roots(4,'real'); 2.2.roots 3,'Im'
For Ruby 1.9.x can also use symbol as option: 384.roots 4,:r
Can ask: How many complex roots of x: x.roots(n,'c').size
What's the 3rd 5th root of (4+9i): Complex(4,9).root(5,3)
---------------
Mathematical Foundations
For complex number (x+iy) = a*e^(i*arg) = a*[cos(arg) + i*sin(arg)]
The root values of a number are:
1) root(n) = (x + iy)^(1/n)
2) root(n) = (a*e^(i*arg))^(1/n)
3) root(n,k) = (a*e^i*(arg + 2kPI))^(1/n)
4) root(n,k) = a^(1/n)*(e^i*(arg + 2kPI))^(1/n)
5) root(n,k) = |a^(1/n)|*e^i*(arg + 2kPI)/n
6) root(n,k) = |a^(1/n)|*(cos(arg/n+2kPI/n) + i*sin(arg/n+2kPI/n))
define mag = |a^(1/n)|, theta = arg/n, and delta = 2PI/n
7) root(n,k)= mag*[cos(theta + k*delta) + i*sin(theta + k*delta)], k=0..n-1
Thus, there are n distinct roots (values):
---------------
Ruby currently gives incorrect values for x|y axis angles.
cos PI/2 => 6.12303176911189e-17
sin PI => 1.22460635382238e-16
cos 3*PI/2 => -1.83690953073357e-16
sin 2*PI => -2.44921970764475e-16
These all should be 0.0, which causes incorrect root values there.
I 'fix' these errors by setting aliases of sin|cos to 0.0 if the
absolute value of the other function equals 1.0 so they produce
the correct root values.
=end
# file roots.rb
module Roots
require 'complex'
include Math
def root(n,k=0) # return kth (1..n) value of root n or default for k=0
raise "Root n not an integer > 0" unless n.kind_of?(Integer) && n>0
raise "Index k not an integer >= 0" unless k.kind_of?(Integer) && k>=0
return self if n == 1 || self == 0
mag = abs**n**-1 ; theta = arg/n ; delta = 2*PI/n
return rootn(mag,theta,delta,k>1 ? k-1:0) if kind_of?(Complex)
return rootn(mag,theta,delta,k-1) if k>0 # kth root of n for any real
return mag if self > 0 # pos real default
return -mag if n&1 == 1 # neg real default, n odd
return rootn(mag,theta) # neg real default, n even, 1st ccw root
end
def roots(n,opt=0) # return array of root n values, [] if no value
raise "Root n not an integer > 0" unless n.kind_of?(Integer) && n>0
raise "Invalid option" unless opt == 0 || opt =~ /^(c|e|i|o|r|C|E|I|O|R)/
return [self] if n == 1 || self == 0
mag = abs**n**-1 ; theta = arg/n ; delta = 2*PI/n
roots = []
case opt
when /^(o|O)/ # odd roots 1,3,5...
0.step(n-1,2) {|k| roots << rootn(mag,theta,delta,k)}
when /^(e|E)/ # even roots 2,4,6...
1.step(n-1,2) {|k| roots << rootn(mag,theta,delta,k)}
when /^(r|R)/ # real roots Complex(x,0) = (x+i0)
n.times {|k| x=rootn(mag,theta,delta,k); roots << x if x.imag == 0}
when /^(i|I)/ # imaginry roots Complex(0,y) = (0+iy)
n.times {|k| x=rootn(mag,theta,delta,k); roots << x if x.real == 0}
when /^(c|C)/ # complex roots Complex(x,y) = (x+iy)
n.times {|k| x=rootn(mag,theta,delta,k); roots << x if x.arg*2 % PI != 0}
else # all n roots
n.times {|k| roots << rootn(mag,theta,delta,k)}
end
return roots
end
private # not accessible as methods in mixin class
# Alias sin|cos to fix C lib errors to get 0.0 values for X|Y axis angles.
def sine(x); cos(x).abs == 1 ? 0 : sin(x) end
def cosine(x); sin(x).abs == 1 ? 0 : cos(x) end
def rootn(mag,theta,delta=0,k=0) # root k of n of real|complex
angle_n = theta + k*delta
mag*Complex(cosine(angle_n),sine(angle_n))
end
end
# Mixin 'root' and 'roots' as methods for all number classes..
class Numeric; include Roots end
@jzakiya
Copy link
Author

jzakiya commented Dec 16, 2010

Module 'Roots' provides two methods 'root' and 'roots' which will find all the nth roots of class Numeric numbers (fixnum, bignum, floats, rational, complex, etc).

Copy link

ghost commented Sep 23, 2013

Can you add 1-3 Usage Examples please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment