@@ -67,13 +67,7 @@ public static double expm1(double v) {
6767 }
6868
6969 public static double acos (double v ) {
70- if (isinf (v )) {
71- throwMathDomainValueError ();
72- }
73- if (isnan (v )) {
74- return v ;
75- }
76- return Math .acos (v );
70+ return exceptNaN (Math .acos (v ), v );
7771 }
7872
7973 /**
@@ -108,13 +102,7 @@ public static double acosh(double y) {
108102 }
109103
110104 public static double asin (double v ) {
111- if (isinf (v )) {
112- throwMathDomainValueError ();
113- }
114- if (isnan (v )) {
115- return v ;
116- }
117- return Math .asin (v );
105+ return exceptNaN (Math .asin (v ), v );
118106 }
119107
120108 public static double asinh (double v ) {
@@ -147,17 +135,14 @@ public static double asinh(double v) {
147135 }
148136
149137 public static double atan (double v ) {
150- if (isnan (v )) {
151- return v ;
152- }
153- return Math .atan (v );
138+ return exceptNaN (Math .atan (v ), v );
154139 }
155140
156141 /**
157142 * Compute <i>tanh<sup>-1</sup>y</i>.
158143 *
159144 * @param y
160- * @return x such that <i>tanh x = y</i>
145+ * @return <i>x</i> such that <i>tanh x = y</i>
161146 */
162147 public static double atanh (double y ) {
163148 double absy = Math .abs (y );
@@ -180,44 +165,26 @@ public static double ceil(PyObject v) {
180165 }
181166
182167 public static double ceil (double v ) {
183- if (isnan (v ) || isinf (v )) {
184- return v ;
185- }
186168 return Math .ceil (v );
187169 }
188170
189171 public static double cos (double v ) {
190- if (isinf (v )) {
191- throwMathDomainValueError ();
192- }
193- if (isnan (v )) {
194- return NAN ;
195- }
196- return Math .cos (v );
172+ return exceptNaN (Math .cos (v ), v );
197173 }
198174
199175 public static double cosh (double v ) {
200- return Math .cosh (v );
176+ return exceptInf ( Math .cosh (v ), v );
201177 }
202178
203179 public static double exp (double v ) {
204- if (isninf (v )) {
205- return ZERO ;
206- }
207- if (isnan (v ) || isinf (v )) {
208- return v ;
209- }
210- return check (Math .exp (v ));
180+ return exceptInf (Math .exp (v ), v );
211181 }
212182
213183 public static double floor (PyObject v ) {
214184 return floor (v .asDouble ());
215185 }
216186
217187 public static double floor (double v ) {
218- if (isnan (v ) || isinf (v )) {
219- return v ;
220- }
221188 return Math .floor (v );
222189 }
223190
@@ -232,10 +199,7 @@ public static double log(PyObject v, PyObject base) {
232199 } else {
233200 doubleValue = log (v .asDouble ());
234201 }
235- if (base != null ) {
236- return check (applyLoggedBase (doubleValue , base ));
237- }
238- return doubleValue ;
202+ return (base == null ) ? doubleValue : applyLoggedBase (doubleValue , base );
239203 }
240204
241205 public static double pow (double v , double w ) {
@@ -254,7 +218,7 @@ public static double pow(double v, double w) {
254218 } else if (w > ZERO || ispinf (w )) {
255219 return ZERO ;
256220 } else {
257- throwMathDomainValueError ();
221+ throw mathDomainError ();
258222 }
259223 }
260224 if (isninf (v )) {
@@ -301,7 +265,7 @@ public static double pow(double v, double w) {
301265 }
302266 }
303267 if (v < ZERO && !isIntegral (w )) {
304- throwMathDomainValueError ();
268+ throw mathDomainError ();
305269 }
306270 return Math .pow (v , w );
307271 }
@@ -311,60 +275,39 @@ public static double sin(PyObject v) {
311275 }
312276
313277 public static double sin (double v ) {
314- if (isinf (v )) {
315- throwMathDomainValueError ();
316- }
317- if (isnan (v )) {
318- return v ;
319- }
320- return Math .sin (v );
278+ return exceptNaN (Math .sin (v ), v );
321279 }
322280
323281 public static double sqrt (PyObject v ) {
324282 return sqrt (v .asDouble ());
325283 }
326284
327285 public static double sqrt (double v ) {
328- if (isnan (v )) {
329- return v ;
330- }
331- if (ispinf (v )) {
332- return v ;
333- }
334- if (isninf (v ) || v < MINUS_ZERO ) {
335- throwMathDomainValueError ();
336- }
337- return Math .sqrt (v );
286+ return exceptNaN (Math .sqrt (v ), v );
338287 }
339288
340289 public static double tan (double v ) {
341- if (isnan (v )) {
342- return NAN ;
343- }
344- if (isinf (v )) {
345- throw Py .ValueError ("math domain error" );
346- }
347- return Math .tan (v );
290+ return exceptNaN (Math .tan (v ), v );
348291 }
349292
350293 public static double log10 (PyObject v ) {
351294 if (v instanceof PyLong ) {
352295 int exp [] = new int [1 ];
353296 double x = ((PyLong )v ).scaledDoubleValue (exp );
354297 if (x <= ZERO ) {
355- throwMathDomainValueError ();
298+ throw mathDomainError ();
356299 }
357300 return log10 (x ) + (exp [0 ] * EIGHT ) * log10 (TWO );
358301 }
359302 return log10 (v .asDouble ());
360303 }
361304
362305 public static double sinh (double v ) {
363- return Math .sinh (v );
306+ return exceptInf ( Math .sinh (v ), v );
364307 }
365308
366309 public static double tanh (double v ) {
367- return Math .tanh (v );
310+ return exceptInf ( Math .tanh (v ), v );
368311 }
369312
370313 public static double fabs (double v ) {
@@ -379,10 +322,10 @@ public static double fmod(double v, double w) {
379322 return v ;
380323 }
381324 if (w == ZERO ) {
382- throwMathDomainValueError ();
325+ throw mathDomainError ();
383326 }
384327 if (isinf (v ) && w == ONE ) {
385- throwMathDomainValueError ();
328+ throw mathDomainError ();
386329 }
387330 return v % w ;
388331 }
@@ -468,11 +411,12 @@ public static double hypot(double x, double y) {
468411 }
469412
470413 public static double radians (double v ) {
471- return check ( Math .toRadians (v ) );
414+ return Math .toRadians (v );
472415 }
473416
474417 public static double degrees (double v ) {
475- return check (Math .toDegrees (v ));
418+ // Note that this does not raise overflow in Python: 1e307 -> inf as in Java.
419+ return Math .toDegrees (v );
476420 }
477421
478422 public static boolean isnan (double v ) {
@@ -501,24 +445,27 @@ public static double copysign(double v, double w) {
501445 public static PyLong factorial (double v ) {
502446 if (v == ZERO || v == ONE ) {
503447 return new PyLong (1 );
448+ } else if (v < ZERO || isnan (v ) || isinf (v )) {
449+ throw mathDomainError ();
450+ } else if (!isIntegral (v )) {
451+ throw mathDomainError ();
452+ } else {
453+ // long input should be big enough :-)
454+ long value = (long )v ;
455+ BigInteger bi = new BigInteger (Long .toString (value ));
456+ for (long l = value - 1 ; l > 1 ; l --) {
457+ bi = bi .multiply (new BigInteger (Long .toString (l )));
458+ }
459+ return new PyLong (bi );
504460 }
505- if (v < ZERO || isnan (v ) || isinf (v )) {
506- throwMathDomainValueError ();
507- }
508- if (!isIntegral (v )) {
509- throwMathDomainValueError ();
510- }
511- // long input should be big enough :-)
512- long value = (long )v ;
513- BigInteger bi = new BigInteger (Long .toString (value ));
514- for (long l = value - 1 ; l > 1 ; l --) {
515- bi = bi .multiply (new BigInteger (Long .toString (l )));
516- }
517- return new PyLong (bi );
518461 }
519462
520463 public static double log1p (double v ) {
521- return log (ONE + v );
464+ if (v <= -1. ) {
465+ throw mathDomainError ();
466+ } else {
467+ return Math .log1p (v );
468+ }
522469 }
523470
524471 public static double fsum (final PyObject iterable ) {
@@ -530,7 +477,7 @@ private static double calculateLongLog(PyLong v) {
530477 int exp [] = new int [1 ];
531478 double x = v .scaledDoubleValue (exp );
532479 if (x <= ZERO ) {
533- throwMathDomainValueError ();
480+ throw mathDomainError ();
534481 }
535482 return log (x ) + (exp [0 ] * EIGHT ) * log (TWO );
536483 }
@@ -542,27 +489,23 @@ private static double applyLoggedBase(double loggedValue, PyObject base) {
542489 } else {
543490 loggedBase = log (base .asDouble ());
544491 }
545- return check ( loggedValue / loggedBase ) ;
492+ return loggedValue / loggedBase ;
546493 }
547494
548495 private static double log (double v ) {
549- if (isninf (v ) || v <= ZERO ) {
550- throwMathDomainValueError ();
551- }
552- if (isinf (v ) || isnan (v )) {
553- return v ;
496+ if (v <= 0. ) {
497+ throw mathDomainError ();
498+ } else {
499+ return Math .log (v );
554500 }
555- return Math .log (v );
556501 }
557502
558503 private static double log10 (double v ) {
559- if (isninf (v )) {
560- throwMathDomainValueError ();
561- }
562- if (isinf (v ) || isnan (v )) {
563- return v ;
504+ if (v <= 0. ) {
505+ throw mathDomainError ();
506+ } else {
507+ return Math .log10 (v );
564508 }
565- return Math .log10 (v );
566509 }
567510
568511 private static boolean isninf (double v ) {
@@ -606,25 +549,64 @@ private static PyException mathRangeError() {
606549 return Py .OverflowError ("math range error" );
607550 }
608551
609- private static void throwMathDomainValueError () {
610- throw Py .ValueError ("math domain error" );
611- }
612-
613- private static double check (double v ) {
614- if (isnan (v )) {
615- throwMathDomainValueError ();
616- }
552+ private static double checkOverflow (double v ) {
617553 if (isinf (v )) {
618554 throw Py .OverflowError ("math range error" );
619555 }
620556 return v ;
621557 }
622558
623- private static double checkOverflow (double v ) {
624- if (isinf (v )) {
559+ /**
560+ * Turn a <code>NaN</code> result into a thrown <code>ValueError</code>, a math domain error, if
561+ * the original argument was not itself <code>NaN</code>. Use as:
562+ *
563+ * <pre>
564+ * public static double asin(double v) { return exceptNaN(Math.asin(v), v); }
565+ * </pre>
566+ *
567+ * Note that the original function argument is also supplied to this method. Most Java math
568+ * library methods do exactly what we need for Python, but some return {@value Double#NaN} when
569+ * Python should raise <code>ValueError</code>. This is a brief way to change that.
570+ *
571+ * @param result to return (if we return)
572+ * @param arg to include in check
573+ * @return result if <code>arg</code> was <code>NaN</code> or <code>result</code> was not
574+ * <code>NaN</code>
575+ * @throws PyException (ValueError) if <code>result</code> was <code>NaN</code> and
576+ * <code>arg</code> was not <code>NaN</code>
577+ */
578+ private static double exceptNaN (double result , double arg ) throws PyException {
579+ if (Double .isNaN (result ) && !Double .isNaN (arg )) {
580+ throw mathDomainError ();
581+ } else {
582+ return result ;
583+ }
584+ }
585+
586+ /**
587+ * Turn an infinite result into a thrown <code>OverflowError</code>, a math range error, if the
588+ * original argument was not itself infinite. Use as:
589+ *
590+ * <pre>
591+ * public static double cosh(double v) { return exceptInf( Math.cosh(v), v); }
592+ * </pre>
593+ *
594+ * Note that the original function argument is also supplied to this method. Most Java math
595+ * library methods do exactly what we need for Python, but some return an infinity when Python
596+ * should raise <code>OverflowError</code>. This is a brief way to change that.
597+ *
598+ * @param result to return (if we return)
599+ * @param arg to include in check
600+ * @return result if <code>arg</code> was infinite or <code>result</code> was not infinite
601+ * @throws PyException (ValueError) if <code>result</code> was infinite and <code>arg</code> was
602+ * not infinite
603+ */
604+ private static double exceptInf (double result , double arg ) {
605+ if (Double .isInfinite (result ) && !Double .isInfinite (arg )) {
625606 throw Py .OverflowError ("math range error" );
607+ } else {
608+ return result ;
626609 }
627- return v ;
628610 }
629611
630612 /**
0 commit comments