Correcting complex math

I thought I would extract some of the issues
and ideas raised from the thread 'Math errors'

http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/75cad8ec7b137fd8#

that dealt with taking the roots of negative reals,
like (-27)^(1/3) and extend the math to cover roots
of all real values, positive and negative.

Mathematical foundations

1) i = (-1)^(1/2)
2) i^1 = i
3) i^2 = -1
4) i^3 = -i
5) i^4 = 1
6) Then it repeats, e.g.: i^5 = i*(i^4) = i
7) e^(i*x) = cos(x) + i*sin(x)
8) when x = PI/2 then e^(PI*i/2) = i

For roots (-a)^(1/n) of negative real values:

x = |a^(1/n)|*(-1)^(1/n)
from 2) above
x = |a^(1/n)|*(i^2)^(1/n)
x = |a^(1/n)|*(i)^(2/n)
apply 8) from above
x = |a^{1/n)|*e^(PI*i/2)^(2/n)
x = |a^(1/n)|*e^(PI*i/n)
9) x = |a^(1/n)|*(cos(PI/n) + i*sin(PI/n))

For roots (a)^(1/n) of positive real values:

x = (a)^(1/n)
x = (a*1)^(1/n)
x = |a^(1/n)|*(1)^(1/n)
from 5) above
x = |a^(1/n)|*(i^4))^(1/n)
x = |a^(1/n)|*(i)^(4/n)
apply 8) from above
x = |a^{1/n)|*e^(PI*i/2)^(4/n)
x = |a^(1/n)|*e^(2*PI*i/n)
10) x = |a^(1/n)|*(cos(2*PI/n) + i*sin(2*PI/n))

There are n distinct roots for any real value:

9) and 10) say, the n roots have magnitude |a^(1/n)|
and dstributed counter clockwise (ccw) on unit circle
2*PI/n (360/n) degrees apart, first root at angle PI/n.

To find the n roots of neg real values the ccw spacing is:

11) roots(n,k)=cos(PI/n+2*k*PI/n) + i*sin(PI/n+2*k*PI/n)
              =cos((2*k+1)*PI/n) + i*sin((2*k+1)PI/n)

To find the n roots of pos real values the ccw spacing is:

12) roots(n,k)=cos(PI/n+(2*k+1)*PI/n)+i*sin(PI/n+(2*k+1)*PI/n)
              =cos(2*(k+1)*PI/n) + i*sin(2*(k+1)*PI/n)

where n is the root number and k = 0..n-1 is the kth root

In Ruby these can be coded as:

require 'complex'
include Math

13)
def roots-neg-reals(a,n,k) # a real value, n root, kth root
  (a.abs**n**-1)*Complex(cos((2*k+1)*PI/n),sin((2*k+1)*PI/n))
end

14)
def roots-pos-reals(a,n,k) # a real value, n root, kth root
  (a.abs**n**-1)*Complex(cos(2*(k+1)*PI/n),sin(2*(k+1)*PI/n))
end

When a is negative, n odd, like (-27)^(1/3), only one real root
and (n-1)/2 complex conjugate pairs (CCP), and the real root is
the middle kth ccw root, which is at [cos(PI)+i*sin(PI)].
When n is even there are n/2 CCPs.

When a is positive, n odd, like (32)^(1/5), only (+) real root is
the last ccw root at cos(2*PI)+i*sin(2*PI). Again, (n-1)/2 CCPs.
When n even there are 2 real roots (+ and -) and the rest CCPs.

Ex: In ccw order: (1)^(1/2) = -1,1; (1)^(1/4)= i,-1,-i,1

Checke with 14) with a=1, and n=2, k=0,1 and n=4,k=0,1,2,3

Thus, using 13), 14) as methods in Complex module, a syntax like
Complex(a).root(n,k), etc, can correctly find all the roots.

def Complex.root(a,n,k)
  if a < 0
     roots-neg-reals(a,n,k)
  else
     roots-pos-reals(a,n,k)
  end
end

This is just illustrative of the concept, that could be
incorporatied in the Complex, et al, modules.

This will correct some of the math errors observed in the
previous thread and allow for more features to be correctly added to
the numerical classes.

If this can be made to work, it might be useful.
Two thoughts that occur to me are:

1. The code you show would probably need to use Rational(?),
   otherwise 1/n (or 1.0/n) may not be what one thinks it is.

2. What would one do with a number (Float or Rational)
   which is arbitrarily close to 1/n but which is not 1/n?

I'd also like to take the opportunity of this thread
to suggest removing (!) something from Complex,
unless anyone can make a good case for retaining it:

require "complex"
n = -2 #=> -2
p = 1 #=> 1
cn = Complex( n, 0 ) #=> Complex(-2, 0)
cp = Complex( p, 0 ) #=> Complex(1, 0)
n > p #=> false
cn > p #=> true
cn > cp #=> true

The Complex numbers are not an "ordered field",
at least not in any normally useful sense.

At the moment if either x or y is Complex
then x <=> y is calculated as x.abs <=> y.abs;

# File complex.rb, line 312
  def <=> (other)
    self.abs <=> other.abs
  end

I think that can be misleading (see the examples above),
and I would prefer it if "<=>" and "<", etc,
were *not* defined for Complex,
and if one wants to compare absolute values
then one should do so explicitly.

If you're messing around with complex variables and you come across
the '>' operator, what else would you expect it to do other than
compare absolute values? There's no room for confusion here, it's
just a syntax shortcut like we have in so many other places in Ruby.

···

On Sun, Dec 20, 2009 at 2:51 PM, Colin Bartlett <colinb2r@googlemail.com> wrote:

If this can be made to work, it might be useful.
Two thoughts that occur to me are:

1. The code you show would probably need to use Rational(?),
otherwise 1/n (or 1.0/n) may not be what one thinks it is.

2. What would one do with a number (Float or Rational)
which is arbitrarily close to 1/n but which is not 1/n?

I'd also like to take the opportunity of this thread
to suggest removing (!) something from Complex,
unless anyone can make a good case for retaining it:

require "complex"
n = -2 #=> -2
p = 1 #=> 1
cn = Complex( n, 0 ) #=> Complex(-2, 0)
cp = Complex( p, 0 ) #=> Complex(1, 0)
n > p #=> false
cn > p #=> true
cn > cp #=> true

The Complex numbers are not an "ordered field",
at least not in any normally useful sense.

At the moment if either x or y is Complex
then x <=> y is calculated as x.abs <=> y.abs;

# File complex.rb, line 312
def <=> (other)
self.abs <=> other.abs
end

I think that can be misleading (see the examples above),
and I would prefer it if "<=>" and "<", etc,
were *not* defined for Complex,
and if one wants to compare absolute values
then one should do so explicitly.

--
Paul Smith
http://www.nomadicfun.co.uk

paul@pollyandpaul.co.uk

Done.

robert@fussel ~
$ allruby -r complex -e 'p Complex(1,-1) <=> Complex(-1,1)'
ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-cygwin]
0
ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-cygwin]
-e:1:in `<main>': undefined method `<=>' for (1-1i):Complex (NoMethodError)

robert@fussel ~
$

:slight_smile:

Kind regards

  robert

···

On 20.12.2009 15:51, Colin Bartlett wrote:

I'd also like to take the opportunity of this thread
to suggest removing (!) something from Complex,
unless anyone can make a good case for retaining it:

The Complex numbers are not an "ordered field",
at least not in any normally useful sense.

At the moment if either x or y is Complex
then x <=> y is calculated as x.abs <=> y.abs;

# File complex.rb, line 312
  def <=> (other)
    self.abs <=> other.abs
  end

I think that can be misleading (see the examples above),
and I would prefer it if "<=>" and "<", etc,
were *not* defined for Complex,
and if one wants to compare absolute values
then one should do so explicitly.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

If this can be made to work, it might be useful.
Two thoughts that occur to me are:

1. The code you show would probably need to use Rational(?),
   otherwise 1/n (or 1.0/n) may not be what one thinks it is.

From a mathematical/engineering perspective it is
understood that a root n is a positive integer > 1.
In other words, what number 'r' multiplied by itself
n times equals 'x'.

A coding implementation can do the requisite checks on
all the inputs and raise needed exceptions/warnings.

Of course from an arithmetic perspective (a)^(1/n) can
take any value of n (integer, float, complex) but if
n not a positive integer (or interizable) number > 1
then the discussion here may not apply to those cases.

I think the syntax of (a)^(n^-1) vs (a)^(1/n) makes the
point more mathematical clearer that what you are doing
is finding the nth root of 'a' vs raising 'a' to a
fractional power.

2. What would one do with a number (Float or Rational)
   which is arbitrarily close to 1/n but which is not 1/n?

If a number can be expressed as rational n = b/c then 'c' would be the
root, and 'b' would be the power and
(a)^b^(c^-1), otherwise see comment above.

I'd also like to take the opportunity of this thread
to suggest removing (!) something from Complex,
unless anyone can make a good case for retaining it:

require "complex"
n = -2 #=> -2
p = 1 #=> 1
cn = Complex( n, 0 ) #=> Complex(-2, 0)
cp = Complex( p, 0 ) #=> Complex(1, 0)
n > p #=> false
cn > p #=> true
cn > cp #=> true

The Complex numbers are not an "ordered field",
at least not in any normally useful sense.

At the moment if either x or y is Complex
then x <=> y is calculated as x.abs <=> y.abs;

# File complex.rb, line 312
  def <=> (other)
    self.abs <=> other.abs
  end

I think that can be misleading (see the examples above),
and I would prefer it if "<=>" and "<", etc,
were *not* defined for Complex,
and if one wants to compare absolute values
then one should do so explicitly.

I would agree that <, >, are ambiguous. It's not just
a matter of magnitude size but also angular 'size',

Remember, complex variables are really vectors with
magnitude and direction (angle).

Take the example of a ferris wheel ride. Where you
get on it is angular distance zero from your start.
Once the ride starts, it will eventually be rotating at
some constant speed, with changing angular direction.

However, the max angular distance from the start with be
when you are at the top of the ferris wheel, which is an
angular distance of PI (180) degrees from your start. All
other locations have CCP angular distance from the start.

Thus, any complex number is defined with polar rep of

mag(a)| /_ angle(a)

Therefore, to find all the n roots of real values, I can
change my original code to make it more efficient and
flexible by making it just find the magnitude and angles
of the root locations.

def Complex.root(a,n,k)
  angle = (2*k+1)*PI/n # for 'a' real negative
  angle += PI/n if a > 0 # for 'a' real positive
  mag = a.abs**n**-1
  # The kth root of (a)**n**-1
  mag*Complex(cos(angle),sin(angle))
end

The key is to find the appropriate angle rotation for
'a' positive or negative. Now by finding that angle
and mag values, all the numeric classes can be written
to find all the roots of real values with easy syntax.

In Integer/Float you could now do:

a.root(n) # default to +/- real root or first CCP
a.root(n,k) # kth ccw root
a.roots(n) # array of all (ccw) roots

To make it intuitive (and follow Matz's POLS) let k
roots go from 1st to kth, k = 1..n, which means that
the routine that uses k just needs to subtract 1 from
it before computing the angle.

These features can be integrated within all the other
numeric classes/modules as appropriate.

···

On Dec 20, 9:51 am, Colin Bartlett <colin...@googlemail.com> wrote:

Paul Smith wrote:

to suggest removing (!) something from Complex,

I think that can be misleading (see the examples above),
and I would prefer it if "<=>" and "<", etc,
were *not* defined for Complex,
and if one wants to compare absolute values
then one should do so explicitly.

Agreed.

If you're messing around with complex variables and you come across
the '>' operator, what else would you expect it to do other than
compare absolute values?

I would expect it to be undefined, just as it is for complex numbers in
real-world math.

There's no room for confusion here, it's
just a syntax shortcut like we have in so many other places in Ruby.

And a very poor one. Complex numbers have no intrinsic ordering, and it
is silly to pretend they do. Complex#> is as meaningless as
Integer#color.

--
Paul Smith
http://www.nomadicfun.co.uk

paul@pollyandpaul.co.uk

Best,

···

On Sun, Dec 20, 2009 at 2:51 PM, Colin Bartlett > <colinb2r@googlemail.com> wrote:

--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
--
Posted via http://www.ruby-forum.com/.

I'd also like to take the opportunity of this thread
to suggest removing (!) something from Complex,
unless anyone can make a good case for retaining it:

Done.

robert@fussel ~
$ allruby -r complex -e 'p Complex(1,-1) <=> Complex(-1,1)'
ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-cygwin]
0
ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-cygwin]
-e:1:in `<main>': undefined method `<=>' for (1-1i):Complex (NoMethodError)

Thanks for that! You've embarrassed me into installing Ruby 1.9 for Windows
to check one or two other things! And I'm pleased to see that:

require "complex" ; p Complex( 7, 0 ) % 3

ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]
Complex(1, 0)

ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-mingw32]
in '<main>': undefined method '%' for (7+0i):Complex (NoMethoError)

And whereas in 1.8:
  require "complex"
c7 = Complex( 7, 0 ) #=> Complex(7, 0)
c7n = Complex( -7, 0 ) #=> Complex(-7, 0)
c7i = Complex( 0, 7 ) #=> Complex(0, 7)
c7n <=> c7i #=> 0
c7i <=> c7 #=> 0
c7n <=> c7 #=> 0
require "mathn"
c7 = Complex( 7, 0 ) #=> 7
c7n = Complex( -7, 0 ) #=> -7
c7i = Complex( 0, 7 ) #=> Complex(0, 7)
c7n <=> c7i #=> 0
c7i <=> c7 #=> 0
c7n <=> c7 #=> -1

In 1.9 the "<=>" is not (as you pointed out) defined, so we get
the (from my point of view) desirable "collapse" of the program,
instead of the (from my point of view) inconsistent results of 1.8.

This post from July 2009 seems relevant:
http://redmine.ruby-lang.org/issues/show/1712
... writes

>1.8's Complex had a modulus operator (%); 1.9's doesn't, and attempts to use it
raise a NoMethodError for #floor because it falls back to Numeric#%
which needs #floor. Is this omission intentional? If so,
could an appropriate NoMethodError be raised instead?
If not, I'd appreciate knowing so I can write the specifications.

I don't think there's natural definition of modulo on complex numbers,
so that we should undefine % method. We might need to do something
for compatibility's sake. Opinion?
              matz.

Does anyone know of any other threads on this?

*** OffTopic ***
  > remember.guy do |as, often| as.you_can - without end
I doubt if I understood 5% (if that) of the technical parts of Guy
Decoux's posts.
Which is to say, given his terse style, almost every part of his posts.
But even I could detect a rather endearing underlying humour in those posts.

···

On Sun, Dec 20, 2009 at 3:15 PM, Robert Klemme <shortcutter@googlemail.com> wrote:

On 20.12.2009 15:51, Colin Bartlett wrote:

Example implementation for class Integer.
Output can be prettyfied if desired, but it's a start.

class Integer
  require 'complex'
  include Math

  def root(n,k=0) # k=1..n, k=0 default root
    return 'Invalid root: n not > 0' if n < 1
    return self if n == 1
    return 0 if self == 0
    mag = self.abs**n**-1
    if k==0 # return default roots
      return mag if self > 0
      return -1*mag if (n & 1) == 1 # n odd
      return mag*Complex(cos(PI/n),sin(PI/n))
    end

    # return kth root if root value
    k -= 1 # translate k = 1..n to k = 0..(n-1)
    angle = (2*k+1)*PI/n # self negative
    angle += PI/n if self > 0 # self positive
    mag*Complex(cos(angle),sin(angle))
  end

  def roots(n)
    return 'Invalid root: n not > 0' if n < 1
    return self if n == 1
    return 0 if self == 0
    mag = self.abs**n**-1
    roots = [] ; theta = PI/n
    n.times do |k|
      angle=(2*k+1)*theta # for neg integer
      angle += theta if self > 0 # for pos integer
      roots << mag*Complex(cos(angle), sin(angle))
    end
    return roots
  end
end

···

On Dec 20, 1:05 pm, jzakiya <jzak...@gmail.com> wrote:

On Dec 20, 9:51 am, Colin Bartlett <colin...@googlemail.com> wrote:

> If this can be made to work, it might be useful.
> Two thoughts that occur to me are:

> 1. The code you show would probably need to use Rational(?),
> otherwise 1/n (or 1.0/n) may not be what one thinks it is.

From a mathematical/engineering perspective it is
understood that a root n is a positive integer > 1.
In other words, what number 'r' multiplied by itself
n times equals 'x'.

A coding implementation can do the requisite checks on
all the inputs and raise needed exceptions/warnings.

Of course from an arithmetic perspective (a)^(1/n) can
take any value of n (integer, float, complex) but if
n not a positive integer (or interizable) number > 1
then the discussion here may not apply to those cases.

I think the syntax of (a)^(n^-1) vs (a)^(1/n) makes the
point more mathematical clearer that what you are doing
is finding the nth root of 'a' vs raising 'a' to a
fractional power.

> 2. What would one do with a number (Float or Rational)
> which is arbitrarily close to 1/n but which is not 1/n?

If a number can be expressed as rational n = b/c then 'c' would be the
root, and 'b' would be the power and
(a)^b^(c^-1), otherwise see comment above.

> I'd also like to take the opportunity of this thread
> to suggest removing (!) something from Complex,
> unless anyone can make a good case for retaining it:

> require "complex"
> n = -2 #=> -2
> p = 1 #=> 1
> cn = Complex( n, 0 ) #=> Complex(-2, 0)
> cp = Complex( p, 0 ) #=> Complex(1, 0)
> n > p #=> false
> cn > p #=> true
> cn > cp #=> true

> The Complex numbers are not an "ordered field",
> at least not in any normally useful sense.

> At the moment if either x or y is Complex
> then x <=> y is calculated as x.abs <=> y.abs;

> # File complex.rb, line 312
> def <=> (other)
> self.abs <=> other.abs
> end

> I think that can be misleading (see the examples above),
> and I would prefer it if "<=>" and "<", etc,
> were *not* defined for Complex,
> and if one wants to compare absolute values
> then one should do so explicitly.

I would agree that <, >, are ambiguous. It's not just
a matter of magnitude size but also angular 'size',

Remember, complex variables are really vectors with
magnitude and direction (angle).

Take the example of a ferris wheel ride. Where you
get on it is angular distance zero from your start.
Once the ride starts, it will eventually be rotating at
some constant speed, with changing angular direction.

However, the max angular distance from the start with be
when you are at the top of the ferris wheel, which is an
angular distance of PI (180) degrees from your start. All
other locations have CCP angular distance from the start.

Thus, any complex number is defined with polar rep of
>mag(a)| /_ angle(a)

Therefore, to find all the n roots of real values, I can
change my original code to make it more efficient and
flexible by making it just find the magnitude and angles
of the root locations.

def Complex.root(a,n,k)
angle = (2*k+1)*PI/n # for 'a' real negative
angle += PI/n if a > 0 # for 'a' real positive
mag = a.abs**n**-1
# The kth root of (a)**n**-1
mag*Complex(cos(angle),sin(angle))
end

The key is to find the appropriate angle rotation for
'a' positive or negative. Now by finding that angle
and mag values, all the numeric classes can be written
to find all the roots of real values with easy syntax.

In Integer/Float you could now do:

a.root(n) # default to +/- real root or first CCP
a.root(n,k) # kth ccw root
a.roots(n) # array of all (ccw) roots

To make it intuitive (and follow Matz's POLS) let k
roots go from 1st to kth, k = 1..n, which means that
the routine that uses k just needs to subtract 1 from
it before computing the angle.

These features can be integrated within all the other
numeric classes/modules as appropriate.

I see in Python % is invalid for complex numbers.

http://www.webreference.com/programming/python/
http://docs.python.org/reference/expressions.html

···

On Dec 20, 3:12 pm, Colin Bartlett <colin...@googlemail.com> wrote:

On Sun, Dec 20, 2009 at 3:15 PM, Robert Klemme > > <shortcut...@googlemail.com> wrote:
> On 20.12.2009 15:51, Colin Bartlett wrote:

>> I'd also like to take the opportunity of this thread
>> to suggest removing (!) something from Complex,
>> unless anyone can make a good case for retaining it:
> Done.

> robert@fussel ~
> $ allruby -r complex -e 'p Complex(1,-1) <=> Complex(-1,1)'
> ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-cygwin]
> 0
> ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-cygwin]
> -e:1:in `<main>': undefined method `<=>' for (1-1i):Complex (NoMethodError)

Thanks for that! You've embarrassed me into installing Ruby 1.9 for Windows
to check one or two other things! And I'm pleased to see that:

require "complex" ; p Complex( 7, 0 ) % 3

ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]
Complex(1, 0)

ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-mingw32]
in '<main>': undefined method '%' for (7+0i):Complex (NoMethoError)

And whereas in 1.8:
require "complex"
c7 = Complex( 7, 0 ) #=> Complex(7, 0)
c7n = Complex( -7, 0 ) #=> Complex(-7, 0)
c7i = Complex( 0, 7 ) #=> Complex(0, 7)
c7n <=> c7i #=> 0
c7i <=> c7 #=> 0
c7n <=> c7 #=> 0
require "mathn"
c7 = Complex( 7, 0 ) #=> 7
c7n = Complex( -7, 0 ) #=> -7
c7i = Complex( 0, 7 ) #=> Complex(0, 7)
c7n <=> c7i #=> 0
c7i <=> c7 #=> 0
c7n <=> c7 #=> -1

In 1.9 the "<=>" is not (as you pointed out) defined, so we get
the (from my point of view) desirable "collapse" of the program,
instead of the (from my point of view) inconsistent results of 1.8.

This post from July 2009 seems relevant:http://redmine.ruby-lang.org/issues/show/1712
.. writes

> >1.8's Complex had a modulus operator (%); 1.9's doesn't, and attempts to use it
> raise a NoMethodError for #floor because it falls back to Numeric#%
> which needs #floor. Is this omission intentional? If so,
> could an appropriate NoMethodError be raised instead?
> If not, I'd appreciate knowing so I can write the specifications.

I don't think there's natural definition of modulo on complex numbers,
so that we should undefine % method. We might need to do something
for compatibility's sake. Opinion?
matz.

Does anyone know of any other threads on this?

*** OffTopic ***
> remember.guy do |as, often| as.you_can - without end
I doubt if I understood 5% (if that) of the technical parts of Guy
Decoux's posts.
Which is to say, given his terse style, almost every part of his posts.
But even I could detect a rather endearing underlying humour in those posts.

Yes. And < and > are also invalid for complex numbers, at least in Python 3.1.
(I don't use Python, but I've set up Python 3.1 on my computer
to see how it deals with complex numbers and other arithmetic.)

So Ruby (from 1.9) and Python have a measure of agreement
on what you shouldn't do with complex numbers.

Interestingly, in Python 3.1:
  8 ** (1/3) #=> 2.0
-8 ** (1/3) #=> 2.0; as in Ruby, it's evaluated as -(8 ** (1/3))
(-8) ** (1/3) #=> (1.0000000000000002+1.7320508075688772j)
-2 * -2 * -2 #=> -8
(-1) ** (1/3) #=> (0.5000000000000001+0.8660254037844386j)

It seems that what Python is doing is to calculate the "first" n'th root
as (in polar coordinates) exp( i * theta / n ), with 0 <= theta < 2 * pi.
That seems to be a reasonably good and (sort of) consistent rule:
for positive real numbers you get the "positive" real root,
and it works for non-integer n.
And for negative real numbers and integer n
you can generate the remaining roots from the first.

But: I'm not sure I agree with the "automatic" conversion from reals
to complex numbers. (There may be a way to disable that?)
And there's a sort of inconsistency between being able to generate
all the roots for the roots of negative real numbers,
but not being able to do that for the roots of positive real numbers.

Back to Ruby: bearing in mind this from July 2009
  http://osdir.com/ml/ruby-core/2009-08/msg00083.html
    "About An Imaginary Number Literal (Translation)"
    ...
    "Matz supposes there must be someone who use complex numbers often"
    ...
if I'm going to make comments about complex numbers when,
to be honest, I only use them for fun, and then only infrequently,
I had better state my qualifications (and lack of them) for doing so.
A degree in Mathematics completed in 1973: I understood
the arithmetic of complex numbers, but not the real meaning
of complex differentiation and integration. About 5 years ago
I got interested again (at an elementary, not an advanced, level)
and I recommend "Visual Complex Analysis" by Tristram Needham.
http://www.usfca.edu/vca/
  "to replace our rich visual intuition by silly games with 2 x 2 matrices
   has always seemed to me to be the height of folly.
   It is therefore a special pleasure to see Visual Complex Analysis
   with its elegantly illustrated visual approach.
  Yes, he has 2 x 2 matrices—but his are interesting."
  Ian Stewart, NEW SCIENTIST [Ian Stewart is a *real* mathematician!]

Summarising, if only for my benefit, are the following correct?

1. For both real and complex numbers (whether purely imaginary,
   mixed real and imaginary, or with a zero imaginary part)
   the positive n'th root of the absolute magnitude is a unique value
   for non-zero values of n, n being a non-zero integer or real number.
  (For negative n, the n'th root of v is (1/v)**(-1/n) ?)

2. Where n is a non-zero integer, and r is a real number > 0, then
    * if n is odd, there is a unique real (and positive) n'th root;
    * if n is even, there are two real n'th roots, one positive, one negative;

3. Where n is a non-zero integer, and r is a real number < 0, then
    * if n is odd, there is a unique real (and negative) n'th root;
    * if n is even, there is no real n'th root.

4. Where n is a non-zero integer, and c is a complex number != 0
   (regarding any numbers with a zero imaginary part as complex)
   there are n.abs complex roots, all having the same absolute value.

5. Working with complex numbers, a reasonable calculation
   of a "first" n'th root, where n is integer or non-integer,
   is in polar coordinates r ** (1/n) * exp( i * theta / n ),
   where 0 < theta <= 2 * pi;
   for integer n, that generates the remaining n'th roots.

After a quick look at your example implementation:
in the method "roots", near the start, maybe insert something like:
  raise "roots some text: n not an integer" unless n.kind_of?(Integer)
And for consistency in roots maybe return [self] if n == 1 ?

As an afterthought, if one is *not* working with complex numbers,
in what sort of calculations might one want an n'th root of a negative number?

···

On Sun, Dec 20, 2009 at 9:10 PM, jzakiya <jzakiya@gmail.com> wrote:

I see in Python % is invalid for complex numbers.
http://www.webreference.com/programming/python/
http://docs.python.org/reference/expressions.html

I've refactored and added more features to my previous
root>roots definitions and posted new and improved code
as a Roots Module here:

http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/25fca9b317246443#

···

On Dec 21, 8:16 pm, Colin Bartlett <colin...@googlemail.com> wrote:

On Sun, Dec 20, 2009 at 9:10 PM, jzakiya <jzak...@gmail.com> wrote:
> I see in Python % is invalid for complex numbers.
>http://www.webreference.com/programming/python/
>http://docs.python.org/reference/expressions.html

Yes. And < and > are also invalid for complex numbers, at least in Python 31.
(I don't use Python, but I've set up Python 3.1 on my computer
to see how it deals with complex numbers and other arithmetic.)

So Ruby (from 1.9) and Python have a measure of agreement
on what you shouldn't do with complex numbers.

Interestingly, in Python 3.1:
8 ** (1/3) #=> 2.0
-8 ** (1/3) #=> 2.0; as in Ruby, it's evaluated as -(8 ** (1/3))
(-8) ** (1/3) #=> (1.0000000000000002+1.7320508075688772j)
-2 * -2 * -2 #=> -8
(-1) ** (1/3) #=> (0.5000000000000001+0.8660254037844386j)

It seems that what Python is doing is to calculate the "first" n'th root
as (in polar coordinates) exp( i * theta / n ), with 0 <= theta < 2 * pi.
That seems to be a reasonably good and (sort of) consistent rule:
for positive real numbers you get the "positive" real root,
and it works for non-integer n.
And for negative real numbers and integer n
you can generate the remaining roots from the first.

But: I'm not sure I agree with the "automatic" conversion from reals
to complex numbers. (There may be a way to disable that?)
And there's a sort of inconsistency between being able to generate
all the roots for the roots of negative real numbers,
but not being able to do that for the roots of positive real numbers.

Back to Ruby: bearing in mind this from July 2009
http://osdir.com/ml/ruby-core/2009-08/msg00083.html
"About An Imaginary Number Literal (Translation)"
...
"Matz supposes there must be someone who use complex numbers often"
...
if I'm going to make comments about complex numbers when,
to be honest, I only use them for fun, and then only infrequently,
I had better state my qualifications (and lack of them) for doing so.
A degree in Mathematics completed in 1973: I understood
the arithmetic of complex numbers, but not the real meaning
of complex differentiation and integration. About 5 years ago
I got interested again (at an elementary, not an advanced, level)
and I recommend "Visual Complex Analysis" by Tristram Needham.http://www.usfca.edu/vca/
"to replace our rich visual intuition by silly games with 2 x 2 matrices
has always seemed to me to be the height of folly.
It is therefore a special pleasure to see Visual Complex Analysis
with its elegantly illustrated visual approach.
Yes, he has 2 x 2 matrices—but his are interesting."
Ian Stewart, NEW SCIENTIST [Ian Stewart is a *real* mathematician!]

Summarising, if only for my benefit, are the following correct?

1. For both real and complex numbers (whether purely imaginary,
mixed real and imaginary, or with a zero imaginary part)
the positive n'th root of the absolute magnitude is a unique value
for non-zero values of n, n being a non-zero integer or real number.
(For negative n, the n'th root of v is (1/v)**(-1/n) ?)

2. Where n is a non-zero integer, and r is a real number > 0, then
* if n is odd, there is a unique real (and positive) n'th root;
* if n is even, there are two real n'th roots, one positive, one negative;

3. Where n is a non-zero integer, and r is a real number < 0, then
* if n is odd, there is a unique real (and negative) n'th root;
* if n is even, there is no real n'th root.

4. Where n is a non-zero integer, and c is a complex number != 0
(regarding any numbers with a zero imaginary part as complex)
there are n.abs complex roots, all having the same absolute value.

5. Working with complex numbers, a reasonable calculation
of a "first" n'th root, where n is integer or non-integer,
is in polar coordinates r ** (1/n) * exp( i * theta / n ),
where 0 < theta <= 2 * pi;
for integer n, that generates the remaining n'th roots.

After a quick look at your example implementation:
in the method "roots", near the start, maybe insert something like:
raise "roots some text: n not an integer" unless n.kind_of?(Integer)
And for consistency in roots maybe return [self] if n == 1 ?

As an afterthought, if one is *not* working with complex numbers,
in what sort of calculations might one want an n'th root of a negative number?