Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2018, 2024, Oracle and/or its affiliates.
# Copyright (c) 2018, 2026, Oracle and/or its affiliates.
# Copyright (c) 2013, Regents of the University of California
#
# All rights reserved.
Expand Down Expand Up @@ -195,6 +195,24 @@ def test_floor_div():
assert_exception(lambda: 5.4 // 0.0, ZeroDivisionError)


def test_large_int_floor_div():
divisor = 2**130 + 5
quotient = 2**80 + 3
remainder = 2**70 + 7
dividend = quotient * divisor + remainder

assert dividend // divisor == quotient
assert -dividend // divisor == -quotient - 1
assert dividend // -divisor == -quotient - 1
assert -dividend // -divisor == quotient

exact_dividend = quotient * divisor
assert exact_dividend // divisor == quotient
assert -exact_dividend // divisor == -quotient
assert exact_dividend // -divisor == -quotient
assert -exact_dividend // -divisor == quotient


def test_true_div():
assert 1 / 2 == 0.5
assert 108086391056891904 / 30023997515803307 == 3.6
Expand All @@ -211,6 +229,10 @@ def test_int_rfloor_div():


def test_divmod():
assert divmod(7, 3) == (2, 1)
assert divmod(True, True) == (1, 0)
assert int.__divmod__(1, 2.0) is NotImplemented

class Floatable:
def __init__(self, val):
self.val = val
Expand All @@ -226,6 +248,38 @@ def doDivmod(a, b):
assert_exception(lambda: doDivmod(*args), TypeError)


def test_large_int_divmod():
divisor = 2**130 + 5
quotient = 2**80 + 3
remainder = 2**70 + 7
dividend = quotient * divisor + remainder

assert divmod(dividend, divisor) == (quotient, remainder)
assert divmod(-dividend, divisor) == (-quotient - 1, divisor - remainder)
assert divmod(dividend, -divisor) == (-quotient - 1, remainder - divisor)
assert divmod(-dividend, -divisor) == (quotient, -remainder)

exact_dividend = quotient * divisor
assert divmod(exact_dividend, divisor) == (quotient, 0)
assert divmod(-exact_dividend, divisor) == (-quotient, 0)
assert divmod(exact_dividend, -divisor) == (-quotient, 0)
assert divmod(-exact_dividend, -divisor) == (quotient, 0)

assert divmod(3 * divisor + 7, divisor) == (3, 7)

long_divisor = 2**40 + 3
large_quotient = 2**100 + 3
assert divmod(large_quotient * long_divisor + 7, long_divisor) == (large_quotient, 7)

long_dividend = 2**40 + 3
assert divmod(long_dividend, divisor) == (0, long_dividend)

long_quotient = 2**31 + 3
long_divisor = 2**31 + 5
assert divmod(long_quotient * long_divisor + 7, long_divisor) == (long_quotient, 7)
assert divmod(-(2**63), -1) == (2**63, 0)


def test_subclass_ordered_binop():
class A(int):
def __add__(self, other):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ def fun4(test_obj):

class ExceptionTests(unittest.TestCase):

def test_errno_enotsup(self):
self.assertEqual(errno.errorcode[errno.ENOTSUP], "ENOTSUP")

def test_exc_info(self):
typ, val, tb = (None,) * 3
try:
Expand Down
34 changes: 34 additions & 0 deletions graalpython/com.oracle.graal.python.test/src/tests/test_float.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ def test_rounding(self):
assert round(1.123, 2) == 1.12
assert round(1.123, 3) == 1.123
assert round(1.123, 100) == 1.123
assert round(1e23) == 99999999999999991611392
assert round(-1e23) == -99999999999999991611392
assert round(8.98846567431158e307) == 2**1023
import sys
if sys.version_info.minor >= 6:
assert 1.123.__round__(None) == 1
Expand Down Expand Up @@ -928,6 +931,37 @@ def test_format(self):
self.assertEqual(format(NAN, 'F'), 'NAN')
self.assertEqual(format(INF, 'f'), 'inf')
self.assertEqual(format(INF, 'F'), 'INF')
self.assertEqual(format(INF, '07,f'), '0000inf')
self.assertEqual(format(NAN, '07,f'), '0000nan')
self.assertEqual(format(-INF, '07_f'), '-000inf')

def test_negative_zero_format(self):
self.assertEqual(format(0.0, 'zf'), '0.000000')
self.assertEqual(format(-0.0, 'z.1f'), '0.0')
self.assertEqual(format(-0.01, 'z.1f'), '0.0')
self.assertEqual(format(-0.09, 'z.1f'), '-0.1')
self.assertEqual(format(-0.001, 'z.2e'), '-1.00e-03')
self.assertEqual(format(-0.001, 'z.2g'), '-0.001')
self.assertEqual(format(-0.001, 'z.2%'), '-0.10%')

self.assertEqual(format(-0.0, ' z.0f'), ' 0')
self.assertEqual(format(-0.0, '+z.0f'), '+0')
self.assertEqual(format(-0.0, '-z.0f'), '0')
self.assertEqual(format(-0.0, 'z>6.1f'), 'zz-0.0')
self.assertEqual(format(-0.0, 'z>z6.1f'), 'zzz0.0')

self.assertEqual(format(-0, 'z.1f'), '0.0')
self.assertEqual(format(complex(0.0, -0.01), 'z.1f'), '0.0+0.0j')
self.assertEqual(format(complex(-0.0, -0.0), 'z'), '(0+0j)')

with self.assertRaisesRegex(ValueError, 'Negative zero coercion'):
format(0, 'zd')
with self.assertRaisesRegex(ValueError, 'Negative zero coercion'):
format('x', 'zs')
with self.assertRaises(ValueError):
format(0.0, 'z+f')
with self.assertRaises(ValueError):
format(0.0, 'fz')

def test_format_testfile(self):
with open(format_testfile) as testfile:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -123,6 +123,23 @@ def test_complex_formatting():
assert format(MyComplex(3j), "") == "42"
assert format(MyComplex(3j), " <5") == "3j "
assert format(complex(2**53 + 1, 0)) == '(9007199254740992+0j)'
assert format(1j, "+.1") == "+1j"
assert format(1j, " .2") == " 1j"
assert format(1000j, ",.4") == "1,000j"
assert format(1000+2000j, ",") == "(1,000+2,000j)"
assert format(1000j, "#") == "1000.j"
assert format(1+2j, "#") == "(1.+2.j)"
assert format(0j, "+.0") == "+0j"
assert format(1+2j, "+") == "(+1+2j)"


def test_alternate_float_formatting():
assert format(0.0, ".0") == "0e+00"
assert format(1000.0, "#") == "1000.0"
assert format(6.103515625e-05, "#.11g") == "6.1035156250e-05"
assert format(2.220446049250313e-16, "#.038g") == "2.2204460492503130808472633361816406250e-16"
assert format(2.220446049250313e-16j, "#.038g") == (
"0.0000000000000000000000000000000000000+2.2204460492503130808472633361816406250e-16j")


class AnyRepr:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2697,27 +2697,7 @@ static Object doGeneral(VirtualFrame frame, Object x,
@TruffleBoundary
private static BigInteger op(BigInteger x) {
// assumes x >= 0
if (x.equals(BigInteger.ZERO) || x.equals(BigInteger.ONE)) {
return x;
}
BigInteger start = BigInteger.ONE;
BigInteger end = x;
BigInteger result = BigInteger.ZERO;
BigInteger two = BigInteger.valueOf(2);
while (start.compareTo(end) <= 0) {
BigInteger mid = (start.add(end).divide(two));
int cmp = mid.multiply(mid).compareTo(x);
if (cmp == 0) {
return mid;
}
if (cmp < 0) {
start = mid.add(BigInteger.ONE);
result = mid;
} else {
end = mid.subtract(BigInteger.ONE);
}
}
return result;
return x.sqrt();
}

private static void raiseIfNegative(Node inliningTarget, boolean condition, PRaiseNode raiseNode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public enum OSErrorEnum {
EPROTONOSUPPORT(platformSpecific(93, 43), tsLiteral("Protocol not supported")),
ESOCKTNOSUPPORT(platformSpecific(94, 44), tsLiteral("Socket type not supported")),
EOPNOTSUPP(platformSpecific(95, 102), tsLiteral("Operation not supported on transport endpoint")),
ENOTSUP(platformSpecific(95, 102), tsLiteral("Operation not supported")),
ENOTSUP(platformSpecific(95, 45), tsLiteral("Operation not supported")),
EPFNOSUPPORT(platformSpecific(96, 46), tsLiteral("Protocol family not supported")),
EAFNOSUPPORT(platformSpecific(97, 47), tsLiteral("Address family not supported by protocol")),
EADDRINUSE(platformSpecific(98, 48), tsLiteral("Address already in use")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ protected static boolean isPrimitiveFloat(Node inliningTarget, Object cls, Built
@Slot(value = SlotKind.tp_repr, isComplex = true)
@GenerateNodeFactory
public abstract static class StrNode extends AbstractNumericUnaryBuiltin {
public static final Spec spec = new Spec(' ', '>', Spec.NONE, false, Spec.UNSPECIFIED, Spec.NONE, 0, 'r');
public static final Spec spec = new Spec(' ', '>', Spec.NONE, false, false, Spec.UNSPECIFIED, Spec.NONE, 0, 'r');

@Override
protected TruffleString op(double self) {
Expand Down Expand Up @@ -823,11 +823,10 @@ static Object round(VirtualFrame frame, Object x, Object n,
@Specialization
static Object round(Object xObj, @SuppressWarnings("unused") PNone none,
@Bind Node inliningTarget,
@Bind PythonLanguage language,
@Exclusive @Cached CastToJavaDoubleNode cast,
@Cached InlinedConditionProfile nanProfile,
@Cached InlinedConditionProfile infProfile,
@Cached InlinedConditionProfile isLongProfile,
@Cached PyLongFromDoubleNode longFromDoubleNode,
@Exclusive @Cached PRaiseNode raiseNode) {
double x = castToDoubleChecked(inliningTarget, xObj, cast);
if (nanProfile.profile(inliningTarget, Double.isNaN(x))) {
Expand All @@ -837,16 +836,7 @@ static Object round(Object xObj, @SuppressWarnings("unused") PNone none,
throw raiseNode.raise(inliningTarget, PythonErrorType.OverflowError, ErrorMessages.CANNOT_CONVERT_S_TO_INT, "float infinity");
}
double result = round(x, 0, inliningTarget, raiseNode);
if (isLongProfile.profile(inliningTarget, result > Long.MAX_VALUE || result < Long.MIN_VALUE)) {
return PFactory.createInt(language, toBigInteger(result));
} else {
return (long) result;
}
}

@TruffleBoundary
private static BigInteger toBigInteger(double d) {
return BigDecimal.valueOf(d).toBigInteger();
return longFromDoubleNode.execute(inliningTarget, result);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinClassExactProfile;
import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode;
import com.oracle.graal.python.nodes.truffle.PythonIntegerTypes;
import com.oracle.graal.python.nodes.util.NarrowBigIntegerNode;
import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext;
import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;
import com.oracle.graal.python.runtime.PythonContext;
Expand Down Expand Up @@ -890,12 +891,14 @@ static PInt doPiPi(PInt left, PInt right,
@TruffleBoundary
static BigInteger op(BigInteger left, BigInteger right) {
// Math.floorDiv for BigInteger
BigInteger r = left.divide(right);
// if the signs are different and modulo not zero, round down
if ((left.xor(right)).signum() < 0 && (r.multiply(right).compareTo(left)) != 0) {
r = r.subtract(BigInteger.ONE);
int leftSign = left.signum();
if (leftSign == 0 || leftSign == right.signum()) {
return left.divide(right);
}
return r;
BigInteger[] quotientAndRemainder = left.divideAndRemainder(right);
return quotientAndRemainder[1].signum() == 0
? quotientAndRemainder[0]
: quotientAndRemainder[0].subtract(BigInteger.ONE);
}

@SuppressWarnings("unused")
Expand All @@ -911,20 +914,80 @@ public static FloorDivNode create() {
}

@Slot(value = SlotKind.nb_divmod, isComplex = true)
@TypeSystemReference(PythonIntegerTypes.class)
@GenerateNodeFactory
abstract static class DivModNode extends BinaryOpBuiltinNode {

private static final BigInteger LONG_OVERFLOW_VALUE = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);

@Specialization
static Object doGeneric(VirtualFrame frame, Object left, Object right,
static Object doLongLong(long left, long right,
@Bind Node inliningTarget,
@Cached FloorDivNode floorDivNode,
@Cached ModNode modNode) {
Object div = floorDivNode.execute(frame, left, right);
if (div == PNotImplemented.NOT_IMPLEMENTED) {
return PNotImplemented.NOT_IMPLEMENTED;
@Shared @Cached PRaiseNode raiseNode) {
raiseDivisionByZero(inliningTarget, right == 0, raiseNode);
Object quotient;
if (left == Long.MIN_VALUE && right == -1) {
quotient = PFactory.createInt(PythonLanguage.get(inliningTarget), LONG_OVERFLOW_VALUE);
} else {
quotient = Math.floorDiv(left, right);
}
return PFactory.createTuple(PythonLanguage.get(inliningTarget),
new Object[]{quotient, Math.floorMod(left, right)});
}

@Specialization
static Object doPIntLong(PInt left, long right,
@Bind Node inliningTarget,
@Shared @Cached NarrowBigIntegerNode narrowQuotient,
@Shared @Cached NarrowBigIntegerNode narrowRemainder,
@Shared @Cached PRaiseNode raiseNode) {
raiseDivisionByZero(inliningTarget, right == 0, raiseNode);
return doBigInteger(inliningTarget, left.getValue(), PInt.longToBigInteger(right),
narrowQuotient, narrowRemainder);
}

@Specialization
static Object doLongPInt(long left, PInt right,
@Bind Node inliningTarget,
@Shared @Cached NarrowBigIntegerNode narrowQuotient,
@Shared @Cached NarrowBigIntegerNode narrowRemainder,
@Shared @Cached PRaiseNode raiseNode) {
raiseDivisionByZero(inliningTarget, right.isZero(), raiseNode);
return doBigInteger(inliningTarget, PInt.longToBigInteger(left), right.getValue(),
narrowQuotient, narrowRemainder);
}

@Specialization
static Object doPIntPInt(PInt left, PInt right,
@Bind Node inliningTarget,
@Shared @Cached NarrowBigIntegerNode narrowQuotient,
@Shared @Cached NarrowBigIntegerNode narrowRemainder,
@Shared @Cached PRaiseNode raiseNode) {
raiseDivisionByZero(inliningTarget, right.isZero(), raiseNode);
return doBigInteger(inliningTarget, left.getValue(), right.getValue(), narrowQuotient, narrowRemainder);
}

private static Object doBigInteger(Node inliningTarget, BigInteger left, BigInteger right,
NarrowBigIntegerNode narrowQuotient, NarrowBigIntegerNode narrowRemainder) {
BigInteger[] quotientAndRemainder = divmod(left, right);
Object quotient = narrowQuotient.execute(inliningTarget, quotientAndRemainder[0]);
Object remainder = narrowRemainder.execute(inliningTarget, quotientAndRemainder[1]);
return PFactory.createTuple(PythonLanguage.get(inliningTarget), new Object[]{quotient, remainder});
}

@TruffleBoundary
private static BigInteger[] divmod(BigInteger left, BigInteger right) {
BigInteger[] quotientAndRemainder = left.divideAndRemainder(right);
if (quotientAndRemainder[1].signum() != 0 && left.signum() != right.signum()) {
quotientAndRemainder[0] = quotientAndRemainder[0].subtract(BigInteger.ONE);
quotientAndRemainder[1] = quotientAndRemainder[1].add(right);
}
Object mod = modNode.execute(frame, left, right);
return PFactory.createTuple(PythonLanguage.get(inliningTarget), new Object[]{div, mod});
return quotientAndRemainder;
}

@Fallback
static PNotImplemented doGeneric(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") Object right) {
return PNotImplemented.NOT_IMPLEMENTED;
}
}

Expand Down Expand Up @@ -1058,11 +1121,12 @@ static BigInteger opNeg(BigInteger a, BigInteger b) {
if (a.signum() == 0) {
return BigInteger.ZERO;
}
BigInteger mod = a.mod(b.negate());
BigInteger positiveB = b.negate();
BigInteger mod = a.mod(positiveB);
if (mod.signum() == 0) {
return BigInteger.ZERO;
}
return a.mod(b.negate()).subtract(b.negate());
return mod.subtract(positiveB);
}

@SuppressWarnings("unused")
Expand Down Expand Up @@ -2686,6 +2750,9 @@ private static void validateIntegerSpec(Node inliningTarget, PRaiseNode raiseNod
if (Spec.specified(spec.precision)) {
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.PRECISION_NOT_ALLOWED_FOR_INT);
}
if (spec.noNegativeZero && (spec.type == 'b' || spec.type == 'c' || spec.type == 'd' || spec.type == 'o' || spec.type == 'x' || spec.type == 'X' || spec.type == 'n')) {
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.NEGATIVE_ZERO_COERCION_NOT_ALLOWED_IN_INT_FMT);
}
if (spec.type == 'c') {
if (Spec.specified(spec.sign)) {
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.SIGN_NOT_ALLOWED_WITH_C_FOR_INT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ private static Spec getAndValidateSpec(Node inliningTarget, TruffleString format
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.SIGN_NOT_ALLOWED_FOR_STRING_FMT);
}
}
if (spec.noNegativeZero) {
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.NEGATIVE_ZERO_COERCION_NOT_ALLOWED_IN_STRING_FMT);
}
if (spec.alternate) {
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ALTERNATE_NOT_ALLOWED_WITH_STRING_FMT);
}
Expand Down
Loading
Loading