Reputation: 205
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
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
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
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