|
41 | 41 | package com.oracle.graal.python.builtins.objects.ints;
|
42 | 42 |
|
43 | 43 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__LT__;
|
| 44 | +import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError; |
44 | 45 | import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
|
45 | 46 |
|
| 47 | +import java.math.BigDecimal; |
46 | 48 | import java.math.BigInteger;
|
| 49 | +import java.math.RoundingMode; |
47 | 50 | import java.util.List;
|
48 | 51 |
|
49 | 52 | import com.oracle.graal.python.PythonLanguage;
|
|
73 | 76 | import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
|
74 | 77 | import com.oracle.graal.python.nodes.ErrorMessages;
|
75 | 78 | import com.oracle.graal.python.nodes.PGuards;
|
| 79 | +import com.oracle.graal.python.nodes.PRaiseNode; |
76 | 80 | import com.oracle.graal.python.nodes.SpecialMethodNames;
|
77 | 81 | import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
|
78 | 82 | import com.oracle.graal.python.nodes.call.special.LookupAndCallVarargsNode;
|
@@ -324,37 +328,49 @@ public abstract static class TrueDivNode extends PythonBinaryBuiltinNode {
|
324 | 328 | if (right.isZero()) {
|
325 | 329 | throw raise(PythonErrorType.ZeroDivisionError, ErrorMessages.DIVISION_BY_ZERO);
|
326 | 330 | }
|
327 |
| - return op(PInt.longToBigInteger(left), right.getValue()); |
| 331 | + return op(PInt.longToBigInteger(left), right.getValue(), getRaiseNode()); |
328 | 332 | }
|
329 | 333 |
|
330 | 334 | @Specialization
|
331 | 335 | double doPL(PInt left, long right) {
|
332 | 336 | if (right == 0) {
|
333 | 337 | throw raise(PythonErrorType.ZeroDivisionError, ErrorMessages.DIVISION_BY_ZERO);
|
334 | 338 | }
|
335 |
| - return op(left.getValue(), PInt.longToBigInteger(right)); |
| 339 | + return op(left.getValue(), PInt.longToBigInteger(right), getRaiseNode()); |
336 | 340 | }
|
337 | 341 |
|
338 | 342 | @Specialization
|
339 | 343 | double doPP(PInt left, PInt right) {
|
340 | 344 | if (right.isZero()) {
|
341 | 345 | throw raise(PythonErrorType.ZeroDivisionError, ErrorMessages.DIVISION_BY_ZERO);
|
342 | 346 | }
|
343 |
| - return op(left.getValue(), right.getValue()); |
| 347 | + return op(left.getValue(), right.getValue(), getRaiseNode()); |
344 | 348 | }
|
345 | 349 |
|
346 | 350 | /*
|
347 | 351 | * We must take special care to do double conversion late (if possible), to avoid loss of
|
348 | 352 | * precision.
|
349 | 353 | */
|
350 | 354 | @TruffleBoundary
|
351 |
| - private static double op(BigInteger a, BigInteger b) { |
352 |
| - BigInteger[] divideAndRemainder = a.divideAndRemainder(b); |
353 |
| - if (divideAndRemainder[1].equals(BigInteger.ZERO)) { |
354 |
| - return divideAndRemainder[0].doubleValue(); |
355 |
| - } else { |
| 355 | + private static double op(BigInteger a, BigInteger b, PRaiseNode raiseNode) { |
| 356 | + final int precisionOfDouble = 17; |
| 357 | + if (fitsIntoDouble(a) && fitsIntoDouble(b)) { |
356 | 358 | return a.doubleValue() / b.doubleValue();
|
357 | 359 | }
|
| 360 | + BigDecimal aDecimal = new BigDecimal(a); |
| 361 | + BigDecimal bDecimal = new BigDecimal(b); |
| 362 | + int aPrec = aDecimal.precision(); |
| 363 | + int bPrec = bDecimal.precision(); |
| 364 | + BigDecimal result = aDecimal.divide(bDecimal, bPrec - aPrec + precisionOfDouble, RoundingMode.HALF_EVEN); |
| 365 | + double d = result.doubleValue(); |
| 366 | + if (Double.isInfinite(d)) { |
| 367 | + throw raiseNode.raise(OverflowError, ErrorMessages.INTEGER_DIVISION_RESULT_TOO_LARGE); |
| 368 | + } |
| 369 | + return d; |
| 370 | + } |
| 371 | + |
| 372 | + private static boolean fitsIntoDouble(BigInteger x) { |
| 373 | + return x.bitLength() < 53; |
358 | 374 | }
|
359 | 375 |
|
360 | 376 | @SuppressWarnings("unused")
|
@@ -724,7 +740,7 @@ PInt doPLPos(PInt left, long right, @SuppressWarnings("unused") PNone none) {
|
724 | 740 |
|
725 | 741 | @Specialization(guards = "right < 0")
|
726 | 742 | double doPLNeg(PInt left, long right, @SuppressWarnings("unused") PNone none) {
|
727 |
| - return TrueDivNode.op(BigInteger.ONE, op(left.getValue(), -right)); |
| 743 | + return TrueDivNode.op(BigInteger.ONE, op(left.getValue(), -right), getRaiseNode()); |
728 | 744 | }
|
729 | 745 |
|
730 | 746 | @Specialization
|
|
0 commit comments