fix floordiv and divmod by zero for ints and floats

This commit is contained in:
silmeth
2019-02-09 15:15:54 +01:00
parent a6d6f0fcaa
commit 6c56c22f0f
4 changed files with 103 additions and 29 deletions

View File

@@ -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"

View File

@@ -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:

View File

@@ -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()))
}
}

View File

@@ -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 {}",