Skip to content

Commit c7bee80

Browse files
Merge pull request RustPython#1239 from youknowone/fix-divmod
Fix int [r]divmod, Add rfloordiv
2 parents dd9a4a1 + 039cc12 commit c7bee80

File tree

3 files changed

+56
-18
lines changed

3 files changed

+56
-18
lines changed

tests/snippets/builtin_divmod.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
assert divmod(11, 3) == (3, 2)
44
assert divmod(8,11) == (0, 8)
55
assert divmod(0.873, 0.252) == (3.0, 0.11699999999999999)
6+
assert divmod(-86340, 86400) == (-1, 60)
67

78
assert_raises(ZeroDivisionError, lambda: divmod(5, 0), 'divmod by zero')
89
assert_raises(ZeroDivisionError, lambda: divmod(5.0, 0.0), 'divmod by zero')

tests/snippets/ints.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,17 @@
3636
assert (2).__mul__(1) == 2
3737
assert (2).__rmul__(1) == 2
3838
assert (2).__truediv__(1) == 2.0
39+
with assertRaises(ZeroDivisionError):
40+
(2).__truediv__(0)
3941
assert (2).__rtruediv__(1) == 0.5
42+
assert (-2).__floordiv__(3) == -1
43+
with assertRaises(ZeroDivisionError):
44+
(2).__floordiv__(0)
45+
assert (-3).__rfloordiv__(2) == -1
46+
assert (-2).__divmod__(3) == (-1, 1)
47+
with assertRaises(ZeroDivisionError):
48+
(2).__divmod__(0)
49+
assert (-3).__rdivmod__(2) == (-1, -1)
4050
assert (2).__pow__(3) == 8
4151
assert (10).__pow__(-1) == 0.1
4252
assert (2).__rpow__(3) == 9

vm/src/obj/objint.rs

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,29 @@ fn inner_pow(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult {
139139
}
140140

141141
fn inner_mod(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult {
142-
if int2.value != BigInt::zero() {
142+
if int2.value.is_zero() {
143+
Err(vm.new_zero_division_error("integer modulo by zero".to_string()))
144+
} else {
143145
Ok(vm.ctx.new_int(&int1.value % &int2.value))
146+
}
147+
}
148+
149+
fn inner_floordiv(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult {
150+
if int2.value.is_zero() {
151+
Err(vm.new_zero_division_error("integer division by zero".to_string()))
144152
} else {
145-
Err(vm.new_zero_division_error("integer modulo by zero".to_string()))
153+
Ok(vm.ctx.new_int(int1.value.div_floor(&int2.value)))
154+
}
155+
}
156+
157+
fn inner_divmod(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult {
158+
if int2.value.is_zero() {
159+
Err(vm.new_zero_division_error("integer division or modulo by zero".to_string()))
160+
} else {
161+
let (div, modulo) = int1.value.div_mod_floor(&int2.value);
162+
Ok(vm
163+
.ctx
164+
.new_tuple(vec![vm.ctx.new_int(div), vm.ctx.new_int(modulo)]))
146165
}
147166
}
148167

@@ -269,13 +288,18 @@ impl PyInt {
269288
#[pymethod(name = "__floordiv__")]
270289
fn floordiv(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
271290
if objtype::isinstance(&other, &vm.ctx.int_type()) {
272-
let v2 = get_value(&other);
273-
if *v2 != BigInt::zero() {
274-
let modulo = (&self.value % v2 + v2) % v2;
275-
Ok(vm.ctx.new_int((&self.value - modulo) / v2))
276-
} else {
277-
Err(vm.new_zero_division_error("integer floordiv by zero".to_string()))
278-
}
291+
let other = other.payload::<PyInt>().unwrap();
292+
inner_floordiv(self, &other, &vm)
293+
} else {
294+
Ok(vm.ctx.not_implemented())
295+
}
296+
}
297+
298+
#[pymethod(name = "__rfloordiv__")]
299+
fn rfloordiv(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
300+
if objtype::isinstance(&other, &vm.ctx.int_type()) {
301+
let other = other.payload::<PyInt>().unwrap();
302+
inner_floordiv(&other, self, &vm)
279303
} else {
280304
Ok(vm.ctx.not_implemented())
281305
}
@@ -397,15 +421,18 @@ impl PyInt {
397421
#[pymethod(name = "__divmod__")]
398422
fn divmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
399423
if objtype::isinstance(&other, &vm.ctx.int_type()) {
400-
let v2 = get_value(&other);
401-
if *v2 != BigInt::zero() {
402-
let (r1, r2) = self.value.div_rem(v2);
403-
Ok(vm
404-
.ctx
405-
.new_tuple(vec![vm.ctx.new_int(r1), vm.ctx.new_int(r2)]))
406-
} else {
407-
Err(vm.new_zero_division_error("integer divmod by zero".to_string()))
408-
}
424+
let other = other.payload::<PyInt>().unwrap();
425+
inner_divmod(self, &other, vm)
426+
} else {
427+
Ok(vm.ctx.not_implemented())
428+
}
429+
}
430+
431+
#[pymethod(name = "__rdivmod__")]
432+
fn rdivmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
433+
if objtype::isinstance(&other, &vm.ctx.int_type()) {
434+
let other = other.payload::<PyInt>().unwrap();
435+
inner_divmod(&other, self, vm)
409436
} else {
410437
Ok(vm.ctx.not_implemented())
411438
}

0 commit comments

Comments
 (0)