Merge pull request #1521 from janrg/round_to_n_decimals

Implement round(number, digits) for digits != 0
This commit is contained in:
Windel Bouwman
2019-10-14 20:19:40 +02:00
committed by GitHub
2 changed files with 33 additions and 3 deletions

View File

@@ -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__)

View File

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