Skip to content

Commit 6f624c6

Browse files
Merge pull request RustPython#1521 from janrg/round_to_n_decimals
Implement round(number, digits) for digits != 0
2 parents b1684b2 + 4fd38e6 commit 6f624c6

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

tests/snippets/floats.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,15 @@
165165
assert isinstance(1.5.__round__(None), int)
166166
assert 0.5.__round__(None) == 0
167167
assert 1.5.__round__(None) == 2
168+
assert 1.234.__round__(1) == 1.2
169+
assert 1.23456.__round__(4) == 1.2346
170+
assert 1.00000000001.__round__(10) == 1.0
171+
assert 1234.5.__round__(-2) == 1200
172+
assert 1.234.__round__(-1) == 0
173+
assert 1.23456789.__round__(15) == 1.23456789
174+
assert 1.2e300.__round__(-500) == 0
175+
assert 1.234.__round__(500) == 1.234
176+
assert 1.2e-300.__round__(299) == 0
168177
assert_raises(TypeError, lambda: 0.5.__round__(0.0))
169178
assert_raises(TypeError, lambda: 1.5.__round__(0.0))
170179
assert_raises(OverflowError, float('inf').__round__)

vm/src/obj/objfloat.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use hexf_parse;
22
use num_bigint::{BigInt, ToBigInt};
33
use num_rational::Ratio;
4-
use num_traits::{float::Float, sign::Signed, ToPrimitive, Zero};
4+
use num_traits::{float::Float, pow, sign::Signed, ToPrimitive, Zero};
55

66
use super::objbytes;
77
use super::objint;
@@ -477,7 +477,6 @@ impl PyFloat {
477477
}
478478
}
479479
};
480-
481480
if let Some(ndigits) = ndigits {
482481
if ndigits.is_zero() {
483482
let fract = self.value.fract();
@@ -492,7 +491,29 @@ impl PyFloat {
492491
};
493492
Ok(vm.ctx.new_float(value))
494493
} else {
495-
Ok(vm.ctx.not_implemented())
494+
let ndigits = match ndigits {
495+
ndigits if *ndigits > i32::max_value().to_bigint().unwrap() => i32::max_value(),
496+
ndigits if *ndigits < i32::min_value().to_bigint().unwrap() => i32::min_value(),
497+
_ => ndigits.to_i32().unwrap(),
498+
};
499+
if (self.value > 1e+16_f64 && ndigits >= 0i32)
500+
|| (ndigits + self.value.log10().floor() as i32 > 16i32)
501+
{
502+
return Ok(vm.ctx.new_float(self.value));
503+
}
504+
if ndigits >= 0i32 {
505+
Ok(vm.ctx.new_float(
506+
(self.value * pow(10.0, ndigits as usize)).round()
507+
/ pow(10.0, ndigits as usize),
508+
))
509+
} else {
510+
let result = (self.value / pow(10.0, (-ndigits) as usize)).round()
511+
* pow(10.0, (-ndigits) as usize);
512+
if result.is_nan() {
513+
return Ok(vm.ctx.new_float(0.0));
514+
}
515+
Ok(vm.ctx.new_float(result))
516+
}
496517
}
497518
} else {
498519
let fract = self.value.fract();

0 commit comments

Comments
 (0)