diff --git a/tests/snippets/floats.py b/tests/snippets/floats.py index aa5cb00a8a..6189314b75 100644 --- a/tests/snippets/floats.py +++ b/tests/snippets/floats.py @@ -165,6 +165,15 @@ assert isinstance(0.5.__round__(None), int) assert isinstance(1.5.__round__(None), int) assert 0.5.__round__(None) == 0 assert 1.5.__round__(None) == 2 +assert 1.234.__round__(1) == 1.2 +assert 1.23456.__round__(4) == 1.2346 +assert 1.00000000001.__round__(10) == 1.0 +assert 1234.5.__round__(-2) == 1200 +assert 1.234.__round__(-1) == 0 +assert 1.23456789.__round__(15) == 1.23456789 +assert 1.2e300.__round__(-500) == 0 +assert 1.234.__round__(500) == 1.234 +assert 1.2e-300.__round__(299) == 0 assert_raises(TypeError, lambda: 0.5.__round__(0.0)) assert_raises(TypeError, lambda: 1.5.__round__(0.0)) assert_raises(OverflowError, float('inf').__round__) diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs index 1c47b160d1..62624bc9c8 100644 --- a/vm/src/obj/objfloat.rs +++ b/vm/src/obj/objfloat.rs @@ -1,7 +1,7 @@ use hexf_parse; use num_bigint::{BigInt, ToBigInt}; use num_rational::Ratio; -use num_traits::{float::Float, sign::Signed, ToPrimitive, Zero}; +use num_traits::{float::Float, pow, sign::Signed, ToPrimitive, Zero}; use super::objbytes; use super::objint; @@ -477,7 +477,6 @@ impl PyFloat { } } }; - if let Some(ndigits) = ndigits { if ndigits.is_zero() { let fract = self.value.fract(); @@ -492,7 +491,29 @@ impl PyFloat { }; Ok(vm.ctx.new_float(value)) } else { - Ok(vm.ctx.not_implemented()) + let ndigits = match ndigits { + ndigits if *ndigits > i32::max_value().to_bigint().unwrap() => i32::max_value(), + ndigits if *ndigits < i32::min_value().to_bigint().unwrap() => i32::min_value(), + _ => ndigits.to_i32().unwrap(), + }; + if (self.value > 1e+16_f64 && ndigits >= 0i32) + || (ndigits + self.value.log10().floor() as i32 > 16i32) + { + return Ok(vm.ctx.new_float(self.value)); + } + if ndigits >= 0i32 { + Ok(vm.ctx.new_float( + (self.value * pow(10.0, ndigits as usize)).round() + / pow(10.0, ndigits as usize), + )) + } else { + let result = (self.value / pow(10.0, (-ndigits) as usize)).round() + * pow(10.0, (-ndigits) as usize); + if result.is_nan() { + return Ok(vm.ctx.new_float(0.0)); + } + Ok(vm.ctx.new_float(result)) + } } } else { let fract = self.value.fract();