From f486f3031f484d9c0b64f3fa037b7ac2cc0cfb31 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 11 Aug 2019 22:09:09 +0900 Subject: [PATCH 1/3] Fix int.__divmod__ --- tests/snippets/builtin_divmod.py | 1 + tests/snippets/ints.py | 3 +++ vm/src/obj/objint.rs | 22 +++++++++++++--------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tests/snippets/builtin_divmod.py b/tests/snippets/builtin_divmod.py index 939e1d2d4..ce9bdfba8 100644 --- a/tests/snippets/builtin_divmod.py +++ b/tests/snippets/builtin_divmod.py @@ -3,6 +3,7 @@ from testutils import assert_raises assert divmod(11, 3) == (3, 2) assert divmod(8,11) == (0, 8) assert divmod(0.873, 0.252) == (3.0, 0.11699999999999999) +assert divmod(-86340, 86400) == (-1, 60) assert_raises(ZeroDivisionError, lambda: divmod(5, 0), 'divmod by zero') assert_raises(ZeroDivisionError, lambda: divmod(5.0, 0.0), 'divmod by zero') diff --git a/tests/snippets/ints.py b/tests/snippets/ints.py index 06f9068f3..be684e5d3 100644 --- a/tests/snippets/ints.py +++ b/tests/snippets/ints.py @@ -37,6 +37,9 @@ assert (2).__mul__(1) == 2 assert (2).__rmul__(1) == 2 assert (2).__truediv__(1) == 2.0 assert (2).__rtruediv__(1) == 0.5 +assert (-2).__divmod__(3) == (-1, 1) +with assertRaises(ZeroDivisionError): + (2).__divmod__(0) assert (2).__pow__(3) == 8 assert (10).__pow__(-1) == 0.1 assert (2).__rpow__(3) == 9 diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index 1f10277d9..c7147cf30 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -146,6 +146,17 @@ fn inner_mod(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult { } } +fn inner_divmod(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult { + if int2.value.is_zero() { + Err(vm.new_zero_division_error("integer division or modulo by zero".to_string())) + } else { + let (div, modulo) = int1.value.div_mod_floor(&int2.value); + Ok(vm + .ctx + .new_tuple(vec![vm.ctx.new_int(div), vm.ctx.new_int(modulo)])) + } +} + #[pyimpl] impl PyInt { #[pymethod(name = "__eq__")] @@ -397,15 +408,8 @@ impl PyInt { #[pymethod(name = "__divmod__")] fn divmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if objtype::isinstance(&other, &vm.ctx.int_type()) { - let v2 = get_value(&other); - if *v2 != BigInt::zero() { - let (r1, r2) = self.value.div_rem(v2); - Ok(vm - .ctx - .new_tuple(vec![vm.ctx.new_int(r1), vm.ctx.new_int(r2)])) - } else { - Err(vm.new_zero_division_error("integer divmod by zero".to_string())) - } + let other = other.payload::().unwrap(); + inner_divmod(self, &other, vm) } else { Ok(vm.ctx.not_implemented()) } From e819b9a2e3cb22cf08b0114b6961566333d1068a Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 11 Aug 2019 22:12:21 +0900 Subject: [PATCH 2/3] Add int.__rdivmod__ --- tests/snippets/ints.py | 1 + vm/src/obj/objint.rs | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/tests/snippets/ints.py b/tests/snippets/ints.py index be684e5d3..40f2610f9 100644 --- a/tests/snippets/ints.py +++ b/tests/snippets/ints.py @@ -40,6 +40,7 @@ assert (2).__rtruediv__(1) == 0.5 assert (-2).__divmod__(3) == (-1, 1) with assertRaises(ZeroDivisionError): (2).__divmod__(0) +assert (-3).__rdivmod__(2) == (-1, -1) assert (2).__pow__(3) == 8 assert (10).__pow__(-1) == 0.1 assert (2).__rpow__(3) == 9 diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index c7147cf30..ad9b5fa11 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -415,6 +415,16 @@ impl PyInt { } } + #[pymethod(name = "__rdivmod__")] + fn rdivmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { + if objtype::isinstance(&other, &vm.ctx.int_type()) { + let other = other.payload::().unwrap(); + inner_divmod(&other, self, vm) + } else { + Ok(vm.ctx.not_implemented()) + } + } + #[pymethod(name = "__neg__")] fn neg(&self, _vm: &VirtualMachine) -> BigInt { -(&self.value) From 039cc128527cef83c8f2c48d17df978ff991ec54 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 11 Aug 2019 22:13:04 +0900 Subject: [PATCH 3/3] int.__[r]floordiv__ to use BigInt.div_floor --- tests/snippets/ints.py | 6 ++++++ vm/src/obj/objint.rs | 33 +++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/tests/snippets/ints.py b/tests/snippets/ints.py index 40f2610f9..d05848361 100644 --- a/tests/snippets/ints.py +++ b/tests/snippets/ints.py @@ -36,7 +36,13 @@ assert (2).__rsub__(1) == -1 assert (2).__mul__(1) == 2 assert (2).__rmul__(1) == 2 assert (2).__truediv__(1) == 2.0 +with assertRaises(ZeroDivisionError): + (2).__truediv__(0) assert (2).__rtruediv__(1) == 0.5 +assert (-2).__floordiv__(3) == -1 +with assertRaises(ZeroDivisionError): + (2).__floordiv__(0) +assert (-3).__rfloordiv__(2) == -1 assert (-2).__divmod__(3) == (-1, 1) with assertRaises(ZeroDivisionError): (2).__divmod__(0) diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index ad9b5fa11..847ba4a15 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -139,10 +139,18 @@ fn inner_pow(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult { } fn inner_mod(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult { - if int2.value != BigInt::zero() { - Ok(vm.ctx.new_int(&int1.value % &int2.value)) - } else { + if int2.value.is_zero() { Err(vm.new_zero_division_error("integer modulo by zero".to_string())) + } else { + Ok(vm.ctx.new_int(&int1.value % &int2.value)) + } +} + +fn inner_floordiv(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult { + if int2.value.is_zero() { + Err(vm.new_zero_division_error("integer division by zero".to_string())) + } else { + Ok(vm.ctx.new_int(int1.value.div_floor(&int2.value))) } } @@ -280,13 +288,18 @@ impl PyInt { #[pymethod(name = "__floordiv__")] fn floordiv(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { if objtype::isinstance(&other, &vm.ctx.int_type()) { - let v2 = get_value(&other); - if *v2 != BigInt::zero() { - let modulo = (&self.value % v2 + v2) % v2; - Ok(vm.ctx.new_int((&self.value - modulo) / v2)) - } else { - Err(vm.new_zero_division_error("integer floordiv by zero".to_string())) - } + let other = other.payload::().unwrap(); + inner_floordiv(self, &other, &vm) + } else { + Ok(vm.ctx.not_implemented()) + } + } + + #[pymethod(name = "__rfloordiv__")] + fn rfloordiv(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { + if objtype::isinstance(&other, &vm.ctx.int_type()) { + let other = other.payload::().unwrap(); + inner_floordiv(&other, self, &vm) } else { Ok(vm.ctx.not_implemented()) }