mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-09 22:49:57 +09:00
fix floordiv and divmod by zero for ints and floats
This commit is contained in:
@@ -1,3 +1,17 @@
|
||||
assert divmod(11, 3) == (3, 2)
|
||||
assert divmod(8,11) == (0, 8)
|
||||
assert divmod(0.873, 0.252) == (3.0, 0.11699999999999999)
|
||||
|
||||
try:
|
||||
divmod(5, 0)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
assert False, "Expected divmod by zero to throw ZeroDivisionError"
|
||||
|
||||
try:
|
||||
divmod(5.0, 0.0)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
assert False, "Expected divmod by zero to throw ZeroDivisionError"
|
||||
|
||||
@@ -26,6 +26,27 @@ except ZeroDivisionError:
|
||||
else:
|
||||
assert False, 'Expected ZeroDivisionError'
|
||||
|
||||
try:
|
||||
5 // 0
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
assert False, 'Expected ZeroDivisionError'
|
||||
|
||||
try:
|
||||
5.3 // (-0.0)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
assert False, 'Expected ZeroDivisionError'
|
||||
|
||||
try:
|
||||
divmod(5, 0)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
assert False, 'Expected ZeroDivisionError'
|
||||
|
||||
try:
|
||||
raise ZeroDivisionError('Is an ArithmeticError subclass?')
|
||||
except ArithmeticError:
|
||||
|
||||
@@ -172,9 +172,9 @@ fn float_divmod(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let args = PyFuncArgs::new(vec![i.clone(), i2.clone()], vec![]);
|
||||
if objtype::isinstance(i2, &vm.ctx.float_type()) || objtype::isinstance(i2, &vm.ctx.int_type())
|
||||
{
|
||||
let r1 = float_floordiv(vm, args.clone());
|
||||
let r2 = float_mod(vm, args.clone());
|
||||
Ok(vm.ctx.new_tuple(vec![r1.unwrap(), r2.unwrap()]))
|
||||
let r1 = float_floordiv(vm, args.clone())?;
|
||||
let r2 = float_mod(vm, args.clone())?;
|
||||
Ok(vm.ctx.new_tuple(vec![r1, r2]))
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"Cannot divmod power {} and {}",
|
||||
@@ -190,18 +190,26 @@ fn float_floordiv(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
args,
|
||||
required = [(i, Some(vm.ctx.float_type())), (i2, None)]
|
||||
);
|
||||
if objtype::isinstance(i2, &vm.ctx.float_type()) {
|
||||
Ok(vm.ctx.new_float((get_value(i) / get_value(i2)).floor()))
|
||||
} else if objtype::isinstance(i2, &vm.ctx.int_type()) {
|
||||
Ok(vm
|
||||
.ctx
|
||||
.new_float((get_value(i) / objint::get_value(i2).to_f64().unwrap()).floor()))
|
||||
|
||||
let v1 = get_value(i);
|
||||
let v2 = if objtype::isinstance(i2, &vm.ctx.float_type) {
|
||||
get_value(i2)
|
||||
} else if objtype::isinstance(i2, &vm.ctx.int_type) {
|
||||
objint::get_value(i2)
|
||||
.to_f64()
|
||||
.ok_or_else(|| vm.new_overflow_error("int too large to convert to float".to_string()))?
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
return Err(vm.new_type_error(format!(
|
||||
"Cannot floordiv {} and {}",
|
||||
i.borrow(),
|
||||
i2.borrow()
|
||||
)))
|
||||
)));
|
||||
};
|
||||
|
||||
if v2 != 0.0 {
|
||||
Ok(vm.ctx.new_float((v1 / v2).floor()))
|
||||
} else {
|
||||
Err(vm.new_zero_division_error("float floordiv by zero".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,14 +237,22 @@ fn float_mod(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
args,
|
||||
required = [(i, Some(vm.ctx.float_type())), (i2, None)]
|
||||
);
|
||||
if objtype::isinstance(i2, &vm.ctx.float_type()) {
|
||||
Ok(vm.ctx.new_float(get_value(i) % get_value(i2)))
|
||||
} else if objtype::isinstance(i2, &vm.ctx.int_type()) {
|
||||
Ok(vm
|
||||
.ctx
|
||||
.new_float(get_value(i) % objint::get_value(i2).to_f64().unwrap()))
|
||||
|
||||
let v1 = get_value(i);
|
||||
let v2 = if objtype::isinstance(i2, &vm.ctx.float_type) {
|
||||
get_value(i2)
|
||||
} else if objtype::isinstance(i2, &vm.ctx.int_type) {
|
||||
objint::get_value(i2)
|
||||
.to_f64()
|
||||
.ok_or_else(|| vm.new_overflow_error("int too large to convert to float".to_string()))?
|
||||
} else {
|
||||
Err(vm.new_type_error(format!("Cannot mod {} and {}", i.borrow(), i2.borrow())))
|
||||
return Err(vm.new_type_error(format!("Cannot mod {} and {}", i.borrow(), i2.borrow())));
|
||||
};
|
||||
|
||||
if v2 != 0.0 {
|
||||
Ok(vm.ctx.new_float(v1 % v2))
|
||||
} else {
|
||||
Err(vm.new_zero_division_error("float mod by zero".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,15 +288,22 @@ fn float_truediv(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
args,
|
||||
required = [(i, Some(vm.ctx.float_type())), (i2, None)]
|
||||
);
|
||||
|
||||
let v1 = get_value(i);
|
||||
if objtype::isinstance(i2, &vm.ctx.float_type) {
|
||||
Ok(vm.ctx.new_float(v1 / get_value(i2)))
|
||||
let v2 = if objtype::isinstance(i2, &vm.ctx.float_type) {
|
||||
get_value(i2)
|
||||
} else if objtype::isinstance(i2, &vm.ctx.int_type) {
|
||||
Ok(vm
|
||||
.ctx
|
||||
.new_float(v1 / objint::get_value(i2).to_f64().unwrap()))
|
||||
objint::get_value(i2)
|
||||
.to_f64()
|
||||
.ok_or_else(|| vm.new_overflow_error("int too large to convert to float".to_string()))?
|
||||
} else {
|
||||
Err(vm.new_type_error(format!("Cannot divide {} and {}", i.borrow(), i2.borrow())))
|
||||
return Err(vm.new_type_error(format!("Cannot divide {} and {}", i.borrow(), i2.borrow())));
|
||||
};
|
||||
|
||||
if v2 != 0.0 {
|
||||
Ok(vm.ctx.new_float(v1 / v2))
|
||||
} else {
|
||||
Err(vm.new_zero_division_error("float division by zero".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use super::objfloat;
|
||||
use super::objstr;
|
||||
use super::objtype;
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
use num_integer::Integer;
|
||||
use num_traits::{Pow, Signed, ToPrimitive, Zero};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
@@ -289,7 +290,13 @@ fn int_floordiv(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
required = [(i, Some(vm.ctx.int_type())), (i2, None)]
|
||||
);
|
||||
if objtype::isinstance(i2, &vm.ctx.int_type()) {
|
||||
Ok(vm.ctx.new_int(get_value(i) / get_value(i2)))
|
||||
let (v1, v2) = (get_value(i), get_value(i2));
|
||||
|
||||
if v2 != BigInt::zero() {
|
||||
Ok(vm.ctx.new_int(v1 / v2))
|
||||
} else {
|
||||
Err(vm.new_zero_division_error("integer floordiv by zero".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"Cannot floordiv {} and {}",
|
||||
@@ -462,11 +469,20 @@ fn int_divmod(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
args,
|
||||
required = [(i, Some(vm.ctx.int_type())), (i2, None)]
|
||||
);
|
||||
let args = PyFuncArgs::new(vec![i.clone(), i2.clone()], vec![]);
|
||||
|
||||
if objtype::isinstance(i2, &vm.ctx.int_type()) {
|
||||
let r1 = int_floordiv(vm, args.clone());
|
||||
let r2 = int_mod(vm, args.clone());
|
||||
Ok(vm.ctx.new_tuple(vec![r1.unwrap(), r2.unwrap()]))
|
||||
let v1 = get_value(i);
|
||||
let v2 = get_value(i2);
|
||||
|
||||
if v2 != BigInt::zero() {
|
||||
let (r1, r2) = v1.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()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"Cannot divmod power {} and {}",
|
||||
|
||||
Reference in New Issue
Block a user