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:
1ndahous3 authored and GitHub committed 2026-09-28 21:56:46 +09:00
1 parent d1327131a5
commit af37a76c1f
2 files changed
+36 -8

No files matched your search

+12 -8
View File
@@ -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]
+24
View File
@@ -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