Skip to content

Commit 5063627

Browse files
committed
Fix float.__round__ panic, use new bigint methods
1 parent 7961ec9 commit 5063627

File tree

2 files changed

+28
-32
lines changed

2 files changed

+28
-32
lines changed

vm/src/builtins/float.rs

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use num_bigint::{BigInt, ToBigInt};
22
use num_complex::Complex64;
33
use num_rational::Ratio;
4-
use num_traits::{pow, ToPrimitive, Zero};
4+
use num_traits::{pow, Signed, ToPrimitive, Zero};
5+
use std::f64;
56

67
use super::bytes::PyBytes;
78
use super::int::{self, PyInt, PyIntRef};
@@ -394,46 +395,47 @@ impl PyFloat {
394395
let ndigits = ndigits.flatten();
395396
let value = if let Some(ndigits) = ndigits {
396397
let ndigits = ndigits.borrow_value();
397-
if ndigits.is_zero() {
398+
let float = if ndigits.is_zero() {
398399
let fract = self.value.fract();
399-
let value = if (fract.abs() - 0.5).abs() < std::f64::EPSILON {
400+
if (fract.abs() - 0.5).abs() < f64::EPSILON {
400401
if self.value.trunc() % 2.0 == 0.0 {
401402
self.value - fract
402403
} else {
403404
self.value + fract
404405
}
405406
} else {
406407
self.value.round()
407-
};
408-
vm.ctx.new_float(value)
408+
}
409409
} else {
410-
let ndigits = match ndigits {
411-
ndigits if *ndigits > i32::max_value().to_bigint().unwrap() => i32::max_value(),
412-
ndigits if *ndigits < i32::min_value().to_bigint().unwrap() => i32::min_value(),
413-
_ => ndigits.to_i32().unwrap(),
410+
let ndigits = match ndigits.to_isize() {
411+
Some(n) => n,
412+
None if ndigits.is_positive() => isize::MAX,
413+
None => isize::MIN,
414414
};
415-
if (self.value > 1e+16_f64 && ndigits >= 0i32)
416-
|| (ndigits + self.value.log10().floor() as i32 > 16i32)
417-
{
418-
return Ok(vm.ctx.new_float(self.value));
419-
}
420-
if ndigits >= 0i32 {
421-
vm.ctx.new_float(
422-
(self.value * pow(10.0, ndigits as usize)).round()
423-
/ pow(10.0, ndigits as usize),
424-
)
415+
const NDIGITS_MAX: isize = ((f64::MANTISSA_DIGITS as i32 - f64::MIN_EXP) as f64
416+
* f64::consts::LOG10_2) as isize;
417+
const NDIGITS_MIN: isize =
418+
-(((f64::MAX_EXP + 1) as f64 * f64::consts::LOG10_2) as isize);
419+
if ndigits > NDIGITS_MAX {
420+
self.value
421+
} else if ndigits > NDIGITS_MIN {
422+
0.0f64.copysign(self.value)
423+
} else if ndigits >= 0 {
424+
(self.value * pow(10.0, ndigits as usize)).round() / pow(10.0, ndigits as usize)
425425
} else {
426426
let result = (self.value / pow(10.0, (-ndigits) as usize)).round()
427427
* pow(10.0, (-ndigits) as usize);
428428
if result.is_nan() {
429-
return Ok(vm.ctx.new_float(0.0));
429+
0.0
430+
} else {
431+
result
430432
}
431-
vm.ctx.new_float(result)
432433
}
433-
}
434+
};
435+
vm.ctx.new_float(float)
434436
} else {
435437
let fract = self.value.fract();
436-
let value = if (fract.abs() - 0.5).abs() < std::f64::EPSILON {
438+
let value = if (fract.abs() - 0.5).abs() < f64::EPSILON {
437439
if self.value.trunc() % 2.0 == 0.0 {
438440
self.value - fract
439441
} else {

vm/src/builtins/int.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,11 @@ pub fn bigint_unsigned_mask(v: &BigInt) -> u32 {
133133
v.to_u32()
134134
.or_else(|| v.to_i32().map(|i| i as u32))
135135
.unwrap_or_else(|| {
136-
let (sign, digits) = v.to_u32_digits();
137136
let mut out = 0u32;
138-
for digit in digits {
137+
for digit in v.iter_u32_digits() {
139138
out = out.wrapping_shl(32) | digit;
140139
}
141-
match sign {
140+
match v.sign() {
142141
num_bigint::Sign::Minus => out * -1i32 as u32,
143142
_ => out,
144143
}
@@ -732,12 +731,7 @@ impl PyInt {
732731
/// Returns the number of ones 1 an int. When the number is < 0,
733732
/// then it returns the number of ones of the absolute value.
734733
fn bit_count(&self) -> u32 {
735-
self.value
736-
.to_u32_digits()
737-
.1
738-
.iter()
739-
.map(|n| n.count_ones())
740-
.sum()
734+
self.value.iter_u32_digits().map(|n| n.count_ones()).sum()
741735
}
742736
}
743737

0 commit comments

Comments
 (0)