Bug introduced in 5.2 or earlier and persisting through 12.0.0
Why ArcTan[1, 0. I ]
yields -1.5708+0. I
?
The result should equal to 0
.
Is this a bug?
It looks like a bug.
Perhaps
ArcTan[1, p q + $MinMachineNumber * I]
will be acceptable. The little noise is unlikely to be a numerical problem. The main pitfall is when p q == -$MinMachineNumber * I
, which drops you back into the buggy case.
ArcTan[1. + 0. I, $MinMachineNumber*I]
(* 0. + 0. I *)
Update: Runtime environments for existing code
You can overload ArcTan
with code like this:
Internal`InheritedBlock[{ArcTan},
Unprotect[ArcTan];
ArcTan[x_, y_] := func[x, y];
Protect[ArcTan];
ArcTan[1., 0. I]
]
There are several issues with doing this, and the simplest thing to do is to understand your particular use-case and choose an appropriate compromise.
For instance, here is one possibility:
ClearAll[runWithNewArcTan];
SetAttributes[runWithNewArcTan, HoldAll];
runWithNewArcTan[code_] :=
Internal`InheritedBlock[{ArcTan},
Unprotect[ArcTan];
(* keeps packed arrays from being unpacked *)
ClearAttributes[ArcTan, Listable];
(* makes all ArcTan[x,y] results Complex;
* vectorized formula means it still works on lists
* however, the formula can have rounding errors when y == 0
* of around $MachineEpsilon in magnitude *)
ArcTan[x_, y_] /; ! FreeQ[{x, y}, _Complex] :=
-I Log[(x + I y)/Sqrt[x^2 + y^2]];
Protect[ArcTan];
(* run code *)
code
];
Here is another:
ClearAll[runWithNewArcTan];
SetAttributes[runWithNewArcTan, HoldAll];
runWithNewArcTan[code_] :=
Internal`InheritedBlock[{ArcTan},
Unprotect[ArcTan];
(* keeping Listable attribute means packed arrays will be unpacked *)
(* fix just the buggy values; the patterns tests are not
* vectorized, so the Listable attribute will unpack packed arrays
* even when neither definition below is used. *)
ArcTan[x_, y_] /;
Precision[{x, y}] === MachinePrecision &&
! FreeQ[{x, y}, _Complex] && Positive[x] && y == 0 := 0. + 0. I;
ArcTan[x_, y_] /;
Precision[{x, y}] === MachinePrecision &&
! FreeQ[{x, y}, _Complex] && Negative[x] && y == 0 := Pi + 0. I;
Protect[ArcTan];
(* run code *)
code
];
The last one would work well in code
that does not use packed arrays. I haven't thought of a simple way that would work exactly like ArcTan[x, y]
but fix the bug.
ArcTan[1, 0*I]
instead of non-exact zeroArcTan[1, 0.*I]
$\endgroup$ArcTan[1, p q]
, wherep
is a MachinePrecision complex number andq
is a real number. Letq
be0
, it yeilds-1.5708+0. I
, but it should be0
. And then I found this is because the result ofArcTan[1, 0. I ]
is-1.5708+0. I
during the calculation. $\endgroup$Re[ArcTan[1, (x + I y)]]
andIm[ArcTan[1, (x + I y)]]
in xy plane, and there is no branch cut near x=0 and y=0. $\endgroup$ArcTan[x,y]
in terms of quadrants, implying real arguments, but also give a formula valid for complex numbers,-I Log[(x + I y)/Sqrt[x^2 + y^2]]
. (2) The MKL seems to defineatan2
only for reals. So maybe WRI botched the implementation. The second argument0. I
seems to be a special case, since any small nonzero number yields a correct value. $\endgroup$