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^(ix) = cos(x) + isin(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^(PIi/2)^(2/n)
x = |a^(1/n)|e^(PIi/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 = (a1)^(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^(PIi/2)^(4/n)
x = |a^(1/n)|e^(2PIi/n)
10) x = |a^(1/n)|
(cos(2PI/n) + isin(2*PI/n))

There are n distinct roots for any real value:

  1. 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:

  1. roots(n,k)=cos(PI/n+2kPI/n) + isin(PI/n+2kPI/n)
    =cos((2
    k+1)PI/n) + isin((2*k+1)PI/n)

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

  1. roots(n,k)=cos(PI/n+(2k+1)PI/n)+isin(PI/n+(2k+1)PI/n)
    =cos(2
    (k+1)PI/n) + isin(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

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

def roots-pos-reals(a,n,k) # a real value, n root, kth root
(a.absn-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(2PI)+isin(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.

On Sun, Dec 20, 2009 at 2:51 PM, Colin B.
[email protected] 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.

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.


Paul S.
http://www.nomadicfun.co.uk

[email protected]

On 20.12.2009 15:51, Colin B. 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:

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.

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

Paul S. wrote:

On Sun, Dec 20, 2009 at 2:51 PM, Colin B.
[email protected] 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 S.
http://www.nomadicfun.co.uk

[email protected]

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]Â

On Sun, Dec 20, 2009 at 3:15 PM, Robert K.
[email protected] wrote:

On 20.12.2009 15:51, Colin B. 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 ‘’: 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 Dec 20, 3:12 pm, Colin B. [email protected] wrote:

robert@fussel ~

c7i = Complex( 0, 7 ) #=> Complex(0, 7)

could an appropriate NoMethodError be raised instead?
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.

I see in Python % is invalid for complex numbers.

http://www.webreference.com/programming/python/

On Dec 20, 9:51 am, Colin B. [email protected] 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.

  1. 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.

cn > p #=> true
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.absn-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, 1:05 pm, jzakiya [email protected] wrote:

In other words, what number ‘r’ multiplied by itself
I think the syntax of (a)^(n^-1) vs (a)^(1/n) makes the

cp = Complex( p, 0 ) #=> Complex(1, 0)

File complex.rb, line 312

I would agree that <, >, are ambiguous. It’s not just
However, the max angular distance from the start with be
of the root locations.
‘a’ positive or negative. Now by finding that angle
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.

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.absn-1
if k==0 # return default roots
return mag if self > 0
return -1mag 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.absn-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 Sun, Dec 20, 2009 at 9:10 PM, jzakiya [email protected] wrote:

I see in Python % is invalid for complex numbers.
http://www.webreference.com/programming/python/
6. Expressions — Python 3.11.4 documentation

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
OSDIR
“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 Dec 21, 8:16 pm, Colin B. [email protected] wrote:

on what you shouldn’t do with complex numbers.
That seems to be a reasonably good and (sort of) consistent rule:

the arithmetic of complex numbers, but not the real meaning
Summarising, if only for my benefit, are the following correct?

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?

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#