Kerr
Kerr

Reputation: 205

C# and strange exponentiation of complex numbers

Have been playing around with complex numbers in C#, and I found something interesting. Not sure if its a bug or if I have just missed something, but when I run the following code:

var num = new Complex(0, 1);
var complexPow = Complex.Pow(num, 2);
var numTimesNum = num * num;
Console.WriteLine("Complex.Pow(num, 2) = {0}   num*num = {1}", complexPow.ToString(), numTimesNum.ToString());

I get the following output:

Complex.Pow(num, 2) = (-1, 1.22460635382238E-16)   num*num = (-1, 0)

If memory serves, a complex number times itself should be just -1 with no imaginary part (or rather an imaginary part of 0). So why doesnt Complex.Pow(num, 2) give -1? Where does the 1.22460635382238E-16 come from?

If it matters, I am using mono since Im not in Windows atm. Think it might be 64-bit, since I am running a 64-bit OS, but I am not sure where to check.

Take care, Kerr.

EDIT:

Ok, I explained poorly. I of course mean the square of i is -1, not the square of any complex number. Thanks for pointing it out. A bit tired right now, so my brain doesnt work too well, lol.

EDIT 2:

To clarify something, I have been reading a little math lately and decided to make a small scripting language for fun. Ok, "scripting language" is an over statement, it just evaluates equations and nothing more.

Upvotes: 1

Views: 703

Answers (3)

jason
jason

Reputation: 241621

So why doesnt Complex.Pow(num, 2) give -1? Where does the 1.22460635382238E-16 come from?

Standard issues with floating point representations, and the algorithms that are used to compute Complex.Pow (it's not as simple as you think). Note that 1.22460635382238E-16 is extremely small, close to machine epsilon. Additionally, a key fact here is that (0, 1) is really (1, pi / 2) in polar coordinates, and pi / 2 doesn't have an exact representation in floating point.

If this is at all uncomfortable to you, I recommend reading What Every Computer Scientist Should Know About Floating-Point Arithmetic. It should be required reading for college CS curriculum.

Upvotes: 3

SLaks
SLaks

Reputation: 887365

You're seeing floating-point imprecision.

1.22460635382238E-16 is actually 0.00000000000000012....

Complex.Pow() is probably implemented through De Moivre's formula, using trigonometry to compute arbitrary powers.
It is therefore subject to inaccuracy from both floating-point arithmetic and trig.
It apparently does not have any special-case code for integral powers, which can be simpler.

Ordinary complex multiplication only involves simple arithmetic, so it is not subject to floating-point inaccuracies when the numbers are integral.

Upvotes: 7

Jon Skeet
Jon Skeet

Reputation: 1500225

So why doesnt Complex.Pow(num, 2) give -1? Where does the 1.22460635382238E-16 come from?

I suspect it's a rounding error, basically. It's a very small number, after all. I don't know the details of Complex.Pow, but I wouldn't be at all surprised to find it used some trigonometry somewhere - you may well be observing the fact that pi/2 isn't exactly representable as a double.

The * operation is able to avoid this by being more simply defined - Complex.Pow could be special-cased to just use x * x where the power is 2, but I expect that hasn't been done. Instead, a general algorithm is used which gives an answer very close to the hypothetical one, but which can result in small errors.

Upvotes: 7

Related Questions