mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Floor and ceil exact floats directly in math.floor/math.ceil (#8834)
Assisted-by: Claude Code:claude-opus-5-5
This commit is contained in:
1 parent
d1327131a5
commit
af37a76c1f
2 files changed
+36
-8
No files matched your search
@@ -368,6 +368,11 @@ mod math {
|
||||
|
||||
#[pyfunction]
|
||||
fn ceil(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
// `math_ceil`: an exact float skips the `__ceil__` lookup.
|
||||
if let Some(f) = x.downcast_ref_if_exact::<PyFloat>(vm) {
|
||||
let v = try_f64_to_bigint(f.to_f64().ceil(), vm)?;
|
||||
return Ok(vm.ctx.new_int(v).into());
|
||||
}
|
||||
// Only call __ceil__ if the class defines it - if it exists but is not callable,
|
||||
// the error should be propagated (not fall back to float conversion)
|
||||
if x.class().has_attr(identifier!(vm, __ceil__)) {
|
||||
@@ -378,14 +383,16 @@ mod math {
|
||||
let v = try_f64_to_bigint(v?.to_f64().ceil(), vm)?;
|
||||
return Ok(vm.ctx.new_int(v).into());
|
||||
}
|
||||
Err(vm.new_type_error(format!(
|
||||
"type '{}' doesn't define '__ceil__' method",
|
||||
x.class().name(),
|
||||
)))
|
||||
Err(vm.new_type_error(format!("must be real number, not {}", x.class().name())))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn floor(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
// `math_floor`: an exact float skips the `__floor__` lookup.
|
||||
if let Some(f) = x.downcast_ref_if_exact::<PyFloat>(vm) {
|
||||
let v = try_f64_to_bigint(f.to_f64().floor(), vm)?;
|
||||
return Ok(vm.ctx.new_int(v).into());
|
||||
}
|
||||
// Only call __floor__ if the class defines it - if it exists but is not callable,
|
||||
// the error should be propagated (not fall back to float conversion)
|
||||
if x.class().has_attr(identifier!(vm, __floor__)) {
|
||||
@@ -396,10 +403,7 @@ mod math {
|
||||
let v = try_f64_to_bigint(v?.to_f64().floor(), vm)?;
|
||||
return Ok(vm.ctx.new_int(v).into());
|
||||
}
|
||||
Err(vm.new_type_error(format!(
|
||||
"type '{}' doesn't define '__floor__' method",
|
||||
x.class().name(),
|
||||
)))
|
||||
Err(vm.new_type_error(format!("must be real number, not {}", x.class().name())))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -102,6 +102,30 @@ with assert_raises(TypeError):
|
||||
math.ceil(object())
|
||||
with assert_raises(TypeError):
|
||||
math.floor(object())
|
||||
with assert_raises(TypeError) as cm:
|
||||
math.floor("1.5")
|
||||
assert str(cm.exception) == "must be real number, not str"
|
||||
with assert_raises(TypeError) as cm:
|
||||
math.ceil(None)
|
||||
assert str(cm.exception) == "must be real number, not NoneType"
|
||||
|
||||
assert math.floor(-0.5) == -1 and math.ceil(-0.5) == 0
|
||||
with assert_raises(OverflowError):
|
||||
math.floor(INF)
|
||||
with assert_raises(ValueError):
|
||||
math.ceil(NAN)
|
||||
|
||||
|
||||
class FloatFloor(float):
|
||||
def __floor__(self):
|
||||
return "sub floor"
|
||||
|
||||
def __ceil__(self):
|
||||
return "sub ceil"
|
||||
|
||||
|
||||
assert math.floor(FloatFloor(1.5)) == "sub floor"
|
||||
assert math.ceil(FloatFloor(1.5)) == "sub ceil"
|
||||
|
||||
isclose = math.isclose
|
||||
|
||||
|
||||
Reference in new issue
Block a user