@@ -23,6 +23,9 @@ public class cmath {
2323 /** ln({@link Double#MAX_VALUE}) or a little less */
2424 private static final double NEARLY_LN_DBL_MAX = 709.4361393 ;
2525
26+ /** log<sub>10</sub>e (Ref: Abramowitz & Stegun [1972], p3). */
27+ private static final double LOG10E = 0.43429448190325182765 ;
28+
2629 private static PyComplex c_prodi (PyComplex x ) {
2730 return (PyComplex )x .__mul__ (i );
2831 }
@@ -204,18 +207,6 @@ public static PyComplex exp(PyObject z) {
204207 return exceptNaN (new PyComplex (u , v ), zz );
205208 }
206209
207- public static PyComplex log (PyObject in ) {
208- PyComplex x = complexFromPyObject (in );
209- if (isNaN (x )) {
210- if (Double .isInfinite (x .real ) || Double .isInfinite (x .imag )) {
211- return new PyComplex (Double .POSITIVE_INFINITY , Double .NaN );
212- } else {
213- return PyComplex .NaN ;
214- }
215- }
216- return new PyComplex (Math .log (abs (x )), Math .atan2 (x .imag , x .real ));
217- }
218-
219210 public static double phase (PyObject in ) {
220211 PyComplex x = complexFromPyObject (in );
221212 return Math .atan2 (x .imag , x .real );
@@ -269,36 +260,125 @@ public static boolean isnan(PyObject in) {
269260 return Double .isNaN (x .real ) || Double .isNaN (x .imag );
270261 }
271262
272- public static PyComplex log10 (PyObject in ) {
273- PyComplex x = complexFromPyObject (in );
274- if (isNaN (x )) {
275- if (Double .isInfinite (x .real ) || Double .isInfinite (x .imag )) {
276- return new PyComplex (Double .POSITIVE_INFINITY , Double .NaN );
277- } else {
278- return PyComplex .NaN ;
279- }
280- }
281- double l = abs (x );
282- return new PyComplex (math .log10 (new PyFloat (l )), Math .atan2 (x .imag , x .real )
283- / Math .log (10.0 ));
263+ /**
264+ * Returns the natural logarithm of <i>w</i>.
265+ *
266+ * @param w
267+ * @return ln <i>w</i>
268+ */
269+ public static PyComplex log (PyObject w ) {
270+ PyComplex ww = complexFromPyObject (w );
271+ double u = ww .real , v = ww .imag ;
272+ // The real part of the result is the log of the magnitude.
273+ double lnr = logHypot (u , v );
274+ // The imaginary part of the result is the arg. This may result in a nan.
275+ double theta = Math .atan2 (v , u );
276+ PyComplex z = new PyComplex (lnr , theta );
277+ return exceptNaN (z , ww );
278+ }
279+
280+ /**
281+ * Returns the common logarithm of <i>w</i> (base 10 logarithm).
282+ *
283+ * @param w
284+ * @return log<sub>10</sub><i>w</i>
285+ */
286+ public static PyComplex log10 (PyObject w ) {
287+ PyComplex ww = complexFromPyObject (w );
288+ double u = ww .real , v = ww .imag ;
289+ // The expression is the same as for base e, scaled in magnitude.
290+ double logr = logHypot (u , v ) * LOG10E ;
291+ double theta = Math .atan2 (v , u ) * LOG10E ;
292+ PyComplex z = new PyComplex (logr , theta );
293+ return exceptNaN (z , ww );
284294 }
285295
286- public static PyComplex log (PyObject in , PyObject base ) {
287- return log (complexFromPyObject (in ), complexFromPyObject (base ));
296+ /**
297+ * Returns the logarithm of <i>w</i> to the given base. If the base is not specified, returns
298+ * the natural logarithm of <i>w</i>. There is one branch cut, from 0 along the negative real
299+ * axis to -∞, continuous from above.
300+ *
301+ * @param w
302+ * @param b
303+ * @return log<sub>b</sub><i>w</i>
304+ */
305+ public static PyComplex log (PyObject w , PyObject b ) {
306+ PyComplex ww = complexFromPyObject (w ), bb = complexFromPyObject (b ), z ;
307+ double u = ww .real , v = ww .imag , br = bb .real , bi = bb .imag , x , y ;
308+ // Natural log of w is (x,y)
309+ x = logHypot (u , v );
310+ y = Math .atan2 (v , u );
311+
312+ if (bi != 0. || br <= 0. ) {
313+ // Complex or negative real base requires complex log: general case.
314+ PyComplex lnb = log (bb );
315+ z = (PyComplex )(new PyComplex (x , y )).__div__ (lnb );
316+
317+ } else {
318+ // Real positive base: frequent case. (b = inf or nan ends up here too.)
319+ double lnb = Math .log (br );
320+ z = new PyComplex (x / lnb , y / lnb );
321+ }
322+
323+ return exceptNaN (z , ww );
288324 }
289325
290- public static PyComplex log (PyComplex x , PyComplex base ) {
291- if (isNaN (x )) {
292- if (Double .isInfinite (x .real ) || Double .isInfinite (x .imag )) {
293- return new PyComplex (Double .POSITIVE_INFINITY , Double .NaN );
326+ /**
327+ * Helper function for the log of a complex number, dealing with the log magnitude, and without
328+ * intermediate overflow or underflow. It returns ln <i>r</i>, where <i>r<sup>2</sup> =
329+ * u<sup>2</sup>+v<sup>2</sup></i>. To do this it computes
330+ * ½ln(u<sup>2</sup>+v<sup>2</sup>). Special cases are handled as follows:
331+ * <ul>
332+ * <li>if u or v is NaN, it returns NaN</li>
333+ * <li>if u or v is infinite, it returns positive infinity</li>
334+ * <li>if u and v are both zero, it raises a ValueError</li>
335+ * </ul>
336+ * We have this function instead of <code>Math.log(Math.hypot(u,v))</code> because a valid
337+ * result is still possible even when <code>hypot(u,v)</code> overflows, and because there's no
338+ * point in taking a square root when a log is to follow.
339+ *
340+ * @param u
341+ * @param v
342+ * @return ½ln(u<sup>2</sup>+v<sup>2</sup>)
343+ */
344+ private static double logHypot (double u , double v ) {
345+
346+ if (Double .isInfinite (u ) || Double .isInfinite (v )) {
347+ return Double .POSITIVE_INFINITY ;
348+
349+ } else {
350+ // Cannot overflow, but if u=v=0 will return -inf.
351+ int scale = 0 , ue = Math .getExponent (u ), ve = Math .getExponent (v );
352+ double lnr ;
353+
354+ if (ue < -511 && ve < -511 ) {
355+ // Both u and v are too small to square, or zero. (Just one would be ok.)
356+ scale = 600 ;
357+ } else if (ue > 510 || ve > 510 ) {
358+ // One of these is too big to square and double (or is nan or inf).
359+ scale = -600 ;
360+ }
361+
362+ if (scale == 0 ) {
363+ // Normal case: there is no risk of overflow or log of zero.
364+ lnr = 0.5 * Math .log (u * u + v * v );
365+ } else {
366+ // We must work with scaled values, us = u * 2**n etc..
367+ double us = Math .scalb (u , scale );
368+ double vs = Math .scalb (v , scale );
369+ // rs**2 = r**2 * 2**2n
370+ double rs2 = us * us + vs * vs ;
371+ // So ln(r) = ln(u**2+v**2)/2 = ln(us**2+vs**2)/2 - n ln(2)
372+ lnr = 0.5 * Math .log (rs2 ) - scale * math .LN2 ;
373+ }
374+
375+ // (u,v) = 0 leads to ln(r) = -inf, but that's a domain error
376+ if (lnr == Double .NEGATIVE_INFINITY ) {
377+ throw math .mathDomainError ();
294378 } else {
295- return PyComplex . NaN ;
379+ return lnr ;
296380 }
297381 }
298- double l = abs (x );
299- PyComplex log_base = log (base );
300- return (PyComplex )new PyComplex (math .log (new PyFloat (l )), Math .atan2 (x .imag , x .real ))
301- .__div__ (log_base );
302382 }
303383
304384 public static PyComplex sin (PyObject in ) {
0 commit comments