Skip to content

Commit f3f9c5f

Browse files
committed
[GR-23245] Make test_long pass (fixes round, rshift and comparisons)
PullRequest: graalpython/1115
2 parents 6a2611b + b7fd42f commit f3f9c5f

File tree

7 files changed

+192
-32
lines changed

7 files changed

+192
-32
lines changed

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_long.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
*graalpython.lib-python.3.test.test_long.LongTest.test__format__
12
*graalpython.lib-python.3.test.test_long.LongTest.test_access_to_nonexistent_digit_0
23
*graalpython.lib-python.3.test.test_long.LongTest.test_as_integer_ratio
34
*graalpython.lib-python.3.test.test_long.LongTest.test_bit_length
45
*graalpython.lib-python.3.test.test_long.LongTest.test_bitop_identities
56
*graalpython.lib-python.3.test.test_long.LongTest.test_conversion
7+
*graalpython.lib-python.3.test.test_long.LongTest.test_correctly_rounded_true_division
68
*graalpython.lib-python.3.test.test_long.LongTest.test_division
79
*graalpython.lib-python.3.test.test_long.LongTest.test_float_conversion
810
*graalpython.lib-python.3.test.test_long.LongTest.test_float_overflow
@@ -11,15 +13,17 @@
1113
*graalpython.lib-python.3.test.test_long.LongTest.test_from_bytes
1214
*graalpython.lib-python.3.test.test_long.LongTest.test_huge_lshift
1315
*graalpython.lib-python.3.test.test_long.LongTest.test_huge_lshift_of_zero
16+
*graalpython.lib-python.3.test.test_long.LongTest.test_huge_rshift
1417
*graalpython.lib-python.3.test.test_long.LongTest.test_huge_rshift_of_huge
1518
*graalpython.lib-python.3.test.test_long.LongTest.test_karatsuba
1619
*graalpython.lib-python.3.test.test_long.LongTest.test_logs
1720
*graalpython.lib-python.3.test.test_long.LongTest.test_long
18-
*graalpython.lib-python.3.test.test_long.LongTest.test_format
1921
*graalpython.lib-python.3.test.test_long.LongTest.test_lshift_of_zero
22+
*graalpython.lib-python.3.test.test_long.LongTest.test_mixed_compares
2023
*graalpython.lib-python.3.test.test_long.LongTest.test_mod_division
2124
*graalpython.lib-python.3.test.test_long.LongTest.test_nan_inf
2225
*graalpython.lib-python.3.test.test_long.LongTest.test_negative_shift_count
26+
*graalpython.lib-python.3.test.test_long.LongTest.test_round
2327
*graalpython.lib-python.3.test.test_long.LongTest.test_shift_bool
2428
*graalpython.lib-python.3.test.test_long.LongTest.test_small_ints
2529
*graalpython.lib-python.3.test.test_long.LongTest.test_to_bytes

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,9 +1944,8 @@ public double fabs(long value) {
19441944
}
19451945

19461946
@Specialization
1947-
public PInt fabs(PInt value) {
1948-
BigInteger xabs = value.abs();
1949-
return factory().createInt(xabs);
1947+
public double fabs(PInt value) {
1948+
return Math.abs(value.doubleValueWithOverflow(getRaiseNode()));
19501949
}
19511950

19521951
@Specialization

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,7 @@ boolean eqDbLn(double a, long b) {
936936

937937
@Specialization
938938
boolean eqDbPI(double a, PInt b) {
939-
return Double.isFinite(a) && a == b.doubleValue();
939+
return compareDoubleToLargeInt(a, b) == 0;
940940
}
941941

942942
@Specialization
@@ -962,6 +962,28 @@ Object eqPDb(VirtualFrame frame, PythonNativeObject left, PInt right,
962962
PNotImplemented eq(Object a, Object b) {
963963
return PNotImplemented.NOT_IMPLEMENTED;
964964
}
965+
966+
// adapted from CPython's float_richcompare in floatobject.c
967+
static double compareDoubleToLargeInt(double v, PInt w) {
968+
if (!Double.isFinite(v)) {
969+
return v;
970+
}
971+
int vsign = v == 0.0 ? 0 : v < 0.0 ? -1 : 1;
972+
int wsign = w.isZero() ? 0 : w.isNegative() ? -1 : 1;
973+
if (vsign != wsign) {
974+
return vsign - wsign;
975+
}
976+
if (w.bitLength() <= 48) {
977+
return v - w.doubleValue();
978+
} else {
979+
return compareUsingBigDecimal(v, w.getValue());
980+
}
981+
}
982+
983+
@TruffleBoundary
984+
private static double compareUsingBigDecimal(double v, BigInteger w) {
985+
return new BigDecimal(v).compareTo(new BigDecimal(w));
986+
}
965987
}
966988

967989
@Builtin(name = __NE__, minNumOfPositionalArgs = 2)
@@ -980,7 +1002,7 @@ boolean neDbLn(double a, long b) {
9801002

9811003
@Specialization
9821004
boolean neDbPI(double a, PInt b) {
983-
return !(Double.isFinite(a) && a == b.doubleValue());
1005+
return EqNode.compareDoubleToLargeInt(a, b) != 0;
9841006
}
9851007

9861008
@Specialization
@@ -1024,7 +1046,7 @@ boolean doDL(double x, long y) {
10241046

10251047
@Specialization
10261048
boolean doPI(double x, PInt y) {
1027-
return x < y.doubleValue();
1049+
return EqNode.compareDoubleToLargeInt(x, y) < 0;
10281050
}
10291051

10301052
@Specialization(guards = "fromNativeNode.isFloatSubtype(frame, y, getClass, isSubtype, context)", limit = "1")
@@ -1089,7 +1111,7 @@ boolean doDL(double x, long y) {
10891111

10901112
@Specialization
10911113
boolean doPI(double x, PInt y) {
1092-
return x <= y.doubleValue();
1114+
return EqNode.compareDoubleToLargeInt(x, y) <= 0;
10931115
}
10941116

10951117
@Specialization(guards = "fromNativeNode.isFloatSubtype(frame, y, getClass, isSubtype, context)", limit = "1")
@@ -1154,7 +1176,7 @@ boolean doDL(double x, long y) {
11541176

11551177
@Specialization
11561178
boolean doPI(double x, PInt y) {
1157-
return x > y.doubleValue();
1179+
return EqNode.compareDoubleToLargeInt(x, y) > 0;
11581180
}
11591181

11601182
@Specialization(guards = "fromNativeNode.isFloatSubtype(frame, y, getClass, isSubtype, context)", limit = "1")
@@ -1219,7 +1241,7 @@ boolean doDL(double x, long y) {
12191241

12201242
@Specialization
12211243
boolean doPI(double x, PInt y) {
1222-
return x >= y.doubleValue();
1244+
return EqNode.compareDoubleToLargeInt(x, y) >= 0;
12231245
}
12241246

12251247
@Specialization(guards = "fromNativeNode.isFloatSubtype(frame, y, getClass, isSubtype, context)", limit = "1")

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntBuiltins.java

Lines changed: 154 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -144,22 +144,141 @@ protected void raiseDivisionByZero(boolean cond) {
144144
@TypeSystemReference(PythonArithmeticTypes.class)
145145
abstract static class RoundNode extends PythonBinaryBuiltinNode {
146146
@SuppressWarnings("unused")
147-
@Specialization(guards = "isPNone(n) || isInteger(n)")
148-
public int roundInt(int arg, Object n) {
147+
@Specialization
148+
public int roundIntNone(int arg, PNone n) {
149149
return arg;
150150
}
151151

152152
@SuppressWarnings("unused")
153-
@Specialization(guards = "isPNone(n) || isInteger(n)")
154-
public long roundLong(long arg, Object n) {
153+
@Specialization
154+
public long roundLongNone(long arg, PNone n) {
155155
return arg;
156156
}
157157

158158
@SuppressWarnings("unused")
159-
@Specialization(guards = "isPNone(n) || isInteger(n)")
160-
public PInt roundPInt(PInt arg, Object n) {
159+
@Specialization
160+
public PInt roundPIntNone(PInt arg, PNone n) {
161161
return factory().createInt(arg.getValue());
162162
}
163+
164+
@Specialization
165+
public Object roundLongInt(long arg, int n) {
166+
if (n >= 0) {
167+
return arg;
168+
}
169+
return makeInt(op(arg, n));
170+
}
171+
172+
@Specialization
173+
public Object roundPIntInt(PInt arg, int n) {
174+
if (n >= 0) {
175+
return arg;
176+
}
177+
return makeInt(op(arg.getValue(), n));
178+
}
179+
180+
@Specialization
181+
public Object roundLongLong(long arg, long n) {
182+
if (n >= 0) {
183+
return arg;
184+
}
185+
if (n < Integer.MIN_VALUE) {
186+
return 0;
187+
}
188+
return makeInt(op(arg, (int) n));
189+
}
190+
191+
@Specialization
192+
public Object roundPIntLong(PInt arg, long n) {
193+
if (n >= 0) {
194+
return arg;
195+
}
196+
if (n < Integer.MIN_VALUE) {
197+
return 0;
198+
}
199+
return makeInt(op(arg.getValue(), (int) n));
200+
}
201+
202+
@Specialization
203+
public Object roundPIntLong(long arg, PInt n) {
204+
if (n.isZeroOrPositive()) {
205+
return arg;
206+
}
207+
try {
208+
return makeInt(op(arg, n.intValueExact()));
209+
} catch (ArithmeticException e) {
210+
// n is < -2^31, max. number of base-10 digits in BigInteger is 2^31 * log10(2)
211+
return 0;
212+
}
213+
}
214+
215+
@Specialization
216+
public Object roundPIntPInt(PInt arg, PInt n) {
217+
if (n.isZeroOrPositive()) {
218+
return arg;
219+
}
220+
try {
221+
return makeInt(op(arg.getValue(), n.intValueExact()));
222+
} catch (ArithmeticException e) {
223+
// n is < -2^31, max. number of base-10 digits in BigInteger is 2^31 * log10(2)
224+
return 0;
225+
}
226+
}
227+
228+
@Specialization(guards = {"!isInteger(n)"})
229+
@SuppressWarnings("unused")
230+
public Object roundPIntPInt(Object arg, Object n) {
231+
throw raise(PythonErrorType.TypeError, ErrorMessages.OBJ_CANNOT_BE_INTERPRETED_AS_INTEGER, n);
232+
}
233+
234+
private Object makeInt(BigDecimal d) {
235+
try {
236+
return intValueExact(d);
237+
} catch (ArithmeticException e) {
238+
// does not fit int, so try long
239+
}
240+
try {
241+
return longValueExact(d);
242+
} catch (ArithmeticException e) {
243+
// does not fit long, try BigInteger
244+
}
245+
try {
246+
return factory().createInt(d.toBigIntegerExact());
247+
} catch (ArithmeticException e) {
248+
// has non-zero fractional part, which should not happen
249+
throw CompilerDirectives.shouldNotReachHere("non-integer produced after rounding an integer", e);
250+
}
251+
}
252+
253+
@TruffleBoundary
254+
private static int intValueExact(BigDecimal d) {
255+
return d.intValueExact();
256+
}
257+
258+
@TruffleBoundary
259+
private static long longValueExact(BigDecimal d) {
260+
return d.longValueExact();
261+
}
262+
263+
@TruffleBoundary
264+
private static BigDecimal op(long arg, int n) {
265+
try {
266+
return new BigDecimal(arg).setScale(n, RoundingMode.HALF_EVEN);
267+
} catch (ArithmeticException e) {
268+
// -n exceeds max. number of base-10 digits in BigInteger
269+
return BigDecimal.ZERO;
270+
}
271+
}
272+
273+
@TruffleBoundary
274+
private static BigDecimal op(BigInteger arg, int n) {
275+
try {
276+
return new BigDecimal(arg).setScale(n, RoundingMode.HALF_EVEN);
277+
} catch (ArithmeticException e) {
278+
// -n exceeds max. number of base-10 digits in BigInteger
279+
return BigDecimal.ZERO;
280+
}
281+
}
163282
}
164283

165284
@Builtin(name = SpecialMethodNames.__RADD__, minNumOfPositionalArgs = 2)
@@ -704,7 +823,9 @@ static long doLLFast(long left, long right, @SuppressWarnings("unused") PNone no
704823
result = Math.multiplyExact(result, base);
705824
}
706825
exponent >>= 1;
707-
base = Math.multiplyExact(base, base);
826+
if (exponent != 0) { // prevent overflow in last iteration
827+
base = Math.multiplyExact(base, base);
828+
}
708829
}
709830
return result;
710831
}
@@ -1313,15 +1434,13 @@ long doLL(long left, long right) {
13131434
}
13141435

13151436
@Specialization
1316-
PInt doIPi(int left, PInt right) {
1317-
raiseNegativeShiftCount(!right.isZeroOrPositive());
1318-
return factory().createInt(op(PInt.longToBigInteger(left), right.intValue()));
1437+
Object doIPi(int left, PInt right) {
1438+
return doHugeShift(PInt.longToBigInteger(left), right);
13191439
}
13201440

13211441
@Specialization
1322-
PInt doLPi(long left, PInt right) {
1323-
raiseNegativeShiftCount(!right.isZeroOrPositive());
1324-
return factory().createInt(op(PInt.longToBigInteger(left), right.intValue()));
1442+
Object doLPi(long left, PInt right) {
1443+
return doHugeShift(PInt.longToBigInteger(left), right);
13251444
}
13261445

13271446
@Specialization
@@ -1331,15 +1450,20 @@ PInt doPiI(PInt left, int right) {
13311450
}
13321451

13331452
@Specialization
1334-
PInt doPiL(PInt left, long right) {
1453+
Object doPiL(PInt left, long right) {
13351454
raiseNegativeShiftCount(right < 0);
1336-
return factory().createInt(op(left.getValue(), (int) right));
1455+
int rightI = (int) right;
1456+
if (rightI == right) {
1457+
return factory().createInt(op(left.getValue(), rightI));
1458+
}
1459+
// right is >= 2**31, BigInteger's bitLength is at most 2**31-1
1460+
// therefore the result of shifting right is just the sign bit
1461+
return left.isNegative() ? -1 : 0;
13371462
}
13381463

13391464
@Specialization
1340-
PInt doPInt(PInt left, PInt right) {
1341-
raiseNegativeShiftCount(!right.isZeroOrPositive());
1342-
return factory().createInt(op(left.getValue(), right.intValue()));
1465+
Object doPInt(PInt left, PInt right) {
1466+
return doHugeShift(left.getValue(), right);
13431467
}
13441468

13451469
private void raiseNegativeShiftCount(boolean cond) {
@@ -1354,8 +1478,19 @@ PNotImplemented doGeneric(Object a, Object b) {
13541478
return PNotImplemented.NOT_IMPLEMENTED;
13551479
}
13561480

1481+
private Object doHugeShift(BigInteger left, PInt right) {
1482+
raiseNegativeShiftCount(!right.isZeroOrPositive());
1483+
try {
1484+
return factory().createInt(op(left, right.intValueExact()));
1485+
} catch (ArithmeticException e) {
1486+
// right is >= 2**31, BigInteger's bitLength is at most 2**31-1
1487+
// therefore the result of shifting right is just the sign bit
1488+
return left.signum() < 0 ? -1 : 0;
1489+
}
1490+
}
1491+
13571492
@TruffleBoundary
1358-
public static BigInteger op(BigInteger left, int right) {
1493+
private static BigInteger op(BigInteger left, int right) {
13591494
return left.shiftRight(right);
13601495
}
13611496

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/PInt.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,8 @@ public boolean isOne() {
8282
return value.equals(BigInteger.ONE);
8383
}
8484

85-
@TruffleBoundary(allowInlining = true)
8685
public boolean isZero() {
87-
return value.equals(BigInteger.ZERO);
86+
return value.signum() == 0;
8887
}
8988

9089
@ExportMessage

graalpython/lib-python/3/test/test_long.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,7 @@ def check_truediv(self, a, b, skip_small=True):
821821
self.assertEqual(expected, got, "Incorrectly rounded division {}/{}: "
822822
"expected {}, got {}".format(a, b, expected, got))
823823

824+
@support.impl_detail("cpython specific", graalvm=False)
824825
@support.requires_IEEE_754
825826
def test_correctly_rounded_true_division(self):
826827
# more stringent tests than those above, checking that the

mx.graalpython/native-image.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Requires = language:regex language:llvm
55

66
JavaArgs = -Xmx4G -Dpolyglot.image-build-time.PreinitializeContexts=python
77

8-
Args = -H:MaxRuntimeCompileMethods=8700 \
8+
Args = -H:MaxRuntimeCompileMethods=8800 \
99
-H:+AddAllCharsets \
1010
--initialize-at-build-time=com.oracle.graal.python,com.oracle.truffle.regex,org.antlr.v4,jline,org.fusesource \
1111
--initialize-at-run-time=com.ibm.icu \

0 commit comments

Comments
 (0)