Merge pull request #982 from youknowone/float-fromhex

Add float.fromhex float.hex
This commit is contained in:
coolreader18
2019-05-16 21:33:40 -05:00
committed by GitHub
4 changed files with 151 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ use super::objint;
use super::objstr;
use super::objtype;
use crate::function::OptionalArg;
use crate::obj::objstr::PyStringRef;
use crate::obj::objtype::PyClassRef;
use crate::pyhash;
use crate::pyobject::{
@@ -10,9 +11,10 @@ use crate::pyobject::{
TypeProtocol,
};
use crate::vm::VirtualMachine;
use hexf;
use num_bigint::{BigInt, ToBigInt};
use num_rational::Ratio;
use num_traits::{ToPrimitive, Zero};
use num_traits::{float::Float, ToPrimitive, Zero};
/// Convert a string or number to a floating point number, if possible.
#[pyclass(name = "float")]
@@ -473,6 +475,59 @@ impl PyFloat {
let denom = vm.ctx.new_int(ratio.denom().clone());
Ok(vm.ctx.new_tuple(vec![numer, denom]))
}
#[pymethod]
fn fromhex(repr: PyStringRef, vm: &VirtualMachine) -> PyResult<f64> {
hexf::parse_hexf64(&repr.value, false).or_else(|_| match repr.value.as_ref() {
"nan" => Ok(std::f64::NAN),
"inf" => Ok(std::f64::INFINITY),
"-inf" => Ok(std::f64::NEG_INFINITY),
_ => Err(vm.new_value_error("invalid hexadecimal floating-point string".to_string())),
})
}
#[pymethod]
fn hex(&self, _vm: &VirtualMachine) -> String {
to_hex(self.value)
}
}
fn to_hex(value: f64) -> String {
let (mantissa, exponent, sign) = value.integer_decode();
let sign_fmt = if sign < 0 { "-" } else { "" };
match value {
value if value.is_zero() => format!("{}0x0.0p+0", sign_fmt),
value if value.is_infinite() => format!("{}inf", sign_fmt),
value if value.is_nan() => "nan".to_string(),
_ => {
const BITS: i16 = 52;
const FRACT_MASK: u64 = 0xf_ffff_ffff_ffff;
format!(
"{}0x{:x}.{:013x}p{:+}",
sign_fmt,
mantissa >> BITS,
mantissa & FRACT_MASK,
exponent + BITS
)
}
}
}
#[test]
fn test_to_hex() {
use rand::Rng;
for _ in 0..20000 {
let bytes = rand::thread_rng().gen::<[u64; 1]>();
let f = f64::from_bits(bytes[0]);
if !f.is_finite() {
continue;
}
let hex = to_hex(f);
// println!("{} -> {}", f, hex);
let roundtrip = hexf::parse_hexf64(&hex, false).unwrap();
// println!(" -> {}", roundtrip);
assert!(f == roundtrip, "{} {} {}", f, hex, roundtrip);
}
}
pub type PyFloatRef = PyRef<PyFloat>;