(I'm surprised a bit that nobody noticed this before.) The complex "pow" operator gives completely bogus results with negative exponents. Example:
[artax:pascal]% cat tst.pas program Foo (Output);
var z: Complex;
begin z := Cmplx (5, 0) pow (-1); WriteLn (Re (z) : 5 : 1, Im (z) : 5 : 1) end. [artax:pascal]% gpc tst.pas [artax:pascal]% ./a.out 1.0 0.0
The "Complex_Pow" function in rts/math.pas computes reciprocals as 1 / (x+iy) := (x-iy) / |x+iy|, which is a nonsense. Here is a patch (recycling a Maurice's idea to make it work for too big or too small arguments).
---------------------------------------- function Complex_Pow (z: Complex; y: Integer) = r: Complex; var a, b: Real; begin if y < 0 then begin if Abs (Re (z)) > Abs (Im (z)) then begin a := Im (z) / Re (z); b := Re (z) + Im (z) * a; z := Cmplx (1 / b, -a / b) end else begin if Im (z) = 0 then begin SetReturnAddress (ReturnAddress (0)); RuntimeError (706); { Executed `x pow y' when complex x is zero and y < 0 } RestoreReturnAddress end; a := Re (z) / Im (z); b := Re (z) * a + Im (z); z := Cmplx (a / b, -1 / b); end; y := - y end; r := 1; while y <> 0 do begin if Odd (y) then r := r * z; y := y shr 1; if y <> 0 then z := Sqr (z) end end; -------------------------------------
BTW, are there any serious reasons why the complex "**" operator accepts only _real_ exponents? As far as the RTS is concerned, it would suffice to change "Double" to "Complex" in the declaration of "Complex_Power", but I expect that it needs some compiler magic as well.
Emil Jerabek
Emil Jerabek wrote:
(I'm surprised a bit that nobody noticed this before.)
Me too. #-(
The complex "pow" operator gives completely bogus results with negative exponents. Example:
[artax:pascal]% cat tst.pas program Foo (Output);
var z: Complex;
begin z := Cmplx (5, 0) pow (-1); WriteLn (Re (z) : 5 : 1, Im (z) : 5 : 1) end. [artax:pascal]% gpc tst.pas [artax:pascal]% ./a.out 1.0 0.0
The "Complex_Pow" function in rts/math.pas computes reciprocals as 1 / (x+iy) := (x-iy) / |x+iy|, which is a nonsense.
Yes, should have been | |^2, of course.
Here is a patch (recycling a Maurice's idea to make it work for too big or too small arguments).
Thanks, I'll aply it. (emil8.pas)
BTW, are there any serious reasons why the complex "**" operator accepts only _real_ exponents?
ISO 10206 defines it only for integer and real exponents. I also doubt how usual this notation is in mathematics. (Of course, it can be defined just like for reals, but ARAIR some theorems known from the real power function don't hold in the complex case.)
As far as the RTS is concerned, it would suffice to change "Double" to "Complex" in the declaration of "Complex_Power", but I expect that it needs some compiler magic as well.
Yes, but if we'd really do it, we should probably provide two versions, so the case of real exponents won't be less efficient when it's done in complex.
Frank
Frank wrote:
ISO 10206 defines it only for integer and real exponents. I also doubt how usual this notation is in mathematics. (Of course, it can be defined just like for reals, but ARAIR some theorems known from the real power function don't hold in the complex case.)
Sure. However AFAICS it's not complex _exponent_ but complex _base_ what makes complex power ill-behaved, since complex logarithm is multivalued. Only PositiveReal ** Complex and Complex ** NonnegativeInteger are safe.
Yes, but if we'd really do it, we should probably provide two versions, so the case of real exponents won't be less efficient when it's done in complex.
It's inefficient already. "z ** y" with complex z is evaluated as "Exp (y * Ln (z))", and reals in mixed expressions (such as * ) are converted to Complex type automatically. (At least I assume they do; otherwise I can't understand why 1 * (Inf + i Inf) = NaN + i NaN.)
Emil
(BTW: what does ARAIR mean?)
Emil Jerabek wrote:
Frank wrote:
ISO 10206 defines it only for integer and real exponents. I also doubt how usual this notation is in mathematics. (Of course, it can be defined just like for reals, but ARAIR some theorems known from the real power function don't hold in the complex case.)
Sure. However AFAICS it's not complex _exponent_ but complex _base_ what makes complex power ill-behaved, since complex logarithm is multivalued. Only PositiveReal ** Complex and Complex ** NonnegativeInteger are safe.
I think you're right.
Yes, but if we'd really do it, we should probably provide two versions, so the case of real exponents won't be less efficient when it's done in complex.
It's inefficient already. "z ** y" with complex z is evaluated as "Exp (y * Ln (z))", and reals in mixed expressions (such as * ) are converted to Complex type automatically. (At least I assume they do; otherwise I can't understand why 1 * (Inf + i Inf) = NaN
- i NaN.)
Seems so. But I think I can fix this (not now, since it doesn't seem to be so terribly urgent, but I put it on my list).
With this in mind, should I still provide Complex^Complex (with a separate RTS function)? It's not that much work to do, I just wonder if anyone will use it at all ...
(BTW: what does ARAIR mean?)
It means as much as "as far as I remember, and I can't type". ;-)
Frank