-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aca384a
commit 8e2fb46
Showing
4 changed files
with
168 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[package] | ||
name = "hexf-format" | ||
version = "0.1.0" | ||
authors = ["Jeong YunWon <[email protected]>"] | ||
|
||
description = "Format hexadecimal floats (see also hexf)" | ||
homepage = "https://github.com/lifthrasiir/hexf" | ||
documentation = "https://docs.rs/hexf-format/" | ||
repository = "https://github.com/lifthrasiir/hexf" | ||
license = "CC0-1.0" | ||
|
||
[dependencies] | ||
num-traits = "0.2" | ||
|
||
[dev-dependencies] | ||
rand = "0.5" | ||
hexf-parse = { version = "0.1.0", path = "../parse/" } | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
//! Format hexadecimal float literals. | ||
//! There are two functions `format_hexf32` and `format_hexf64` provided for each type. | ||
//! | ||
//! ```rust | ||
//! use hexf_format::*; | ||
//! assert_eq!(format!("{:x}", Format(0.1f32)), "0x1.99999ap-4"); | ||
//! assert_eq!(format!("{:x}", Format(0.1f64)), "0x1.999999999999ap-4"); | ||
//! ``` | ||
|
||
extern crate num_traits; | ||
|
||
#[cfg(test)] | ||
extern crate hexf_parse; | ||
#[cfg(test)] | ||
extern crate rand; | ||
|
||
use std::{f32, f64, fmt}; | ||
|
||
mod internal { | ||
use num_traits::{float::Float, Signed, Zero}; | ||
use std::fmt; | ||
|
||
pub trait FormatHexf: Signed + Float + Zero { | ||
fn sign_string(&self) -> &'static str { | ||
if self.is_negative() { | ||
"-" | ||
} else { | ||
"" | ||
} | ||
} | ||
fn fmt_normal(&self, f: &mut fmt::Formatter) -> fmt::Result; | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
match self { | ||
v if v.is_zero() => write!(f, "{}0x0.0p+0", v.sign_string()), | ||
v if v.is_infinite() => Err(fmt::Error {}), | ||
v if v.is_nan() => Err(fmt::Error), | ||
_ => self.fmt_normal(f), | ||
} | ||
} | ||
} | ||
|
||
impl FormatHexf for f32 { | ||
fn fmt_normal(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
const BITS: i16 = 23; | ||
const FRACT_MASK: u64 = 0x7f_ffff; | ||
let (mantissa, exponent, _) = self.integer_decode(); | ||
write!( | ||
f, | ||
"{}0x{:x}.{:06x}p{:+}", | ||
self.sign_string(), | ||
mantissa >> BITS, | ||
(mantissa & FRACT_MASK) << 1, | ||
exponent + BITS | ||
) | ||
} | ||
} | ||
|
||
impl FormatHexf for f64 { | ||
fn fmt_normal(&self, f: &mut std::fmt::Formatter) -> fmt::Result { | ||
const BITS: i16 = 52; | ||
const FRACT_MASK: u64 = 0xf_ffff_ffff_ffff; | ||
let (mantissa, exponent, _) = self.integer_decode(); | ||
write!( | ||
f, | ||
"{}0x{:x}.{:013x}p{:+}", | ||
self.sign_string(), | ||
mantissa >> BITS, | ||
mantissa & FRACT_MASK, | ||
exponent + BITS | ||
) | ||
} | ||
} | ||
|
||
} | ||
|
||
pub struct Format<T>(pub T); | ||
|
||
impl<F: internal::FormatHexf> fmt::LowerHex for Format<F> { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
self.0.fmt(f) | ||
} | ||
} | ||
|
||
/// Tries to format an `f32` to hexadecimal. | ||
pub fn format_hexf32(value: f32) -> String { | ||
format!("{:x}", Format(value)) | ||
} | ||
|
||
/// Tries to format an `f64` to hexadecimal. | ||
pub fn format_hexf64(value: f64) -> String { | ||
format!("{:x}", Format(value)) | ||
} | ||
|
||
#[test] | ||
fn test_format_normal_hexf32() { | ||
use hexf_parse::parse_hexf32; | ||
use rand::Rng; | ||
|
||
for _ in 0..20000 { | ||
let bytes = rand::thread_rng().gen::<[u32; 1]>(); | ||
let f = f32::from_bits(bytes[0]); | ||
if !f.is_finite() { | ||
continue; | ||
} | ||
|
||
let hex = format!("{:x}", Format(f)); | ||
// println!("{} -> {}", f, hex); | ||
let roundtrip = parse_hexf32(&hex, false).unwrap(); | ||
// println!(" -> {}", roundtrip); | ||
assert_eq!(f, roundtrip, "{} {} {}", f, hex, roundtrip); | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_format_normal_hexf64() { | ||
use hexf_parse::parse_hexf64; | ||
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 = format!("{:x}", Format(f)); | ||
// println!("{} -> {}", f, hex); | ||
let roundtrip = parse_hexf64(&hex, false).unwrap(); | ||
// println!(" -> {}", roundtrip); | ||
assert_eq!(f, roundtrip, "{} {} {}", f, hex, roundtrip); | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_format_hexf() { | ||
assert_eq!(format!("{:x}", Format(0.0f64)), "0x0.0p+0"); | ||
assert_eq!(format!("{:x}", Format(0.0f32)), "0x0.0p+0"); | ||
assert_eq!(format!("{:x}", Format(-0.0f64)), "-0x0.0p+0"); | ||
assert_eq!(format!("{:x}", Format(-0.0f32)), "-0x0.0p+0"); | ||
|
||
// assert_eq!(f64::INFINITY.format().unwrap_err(), ERR_INFINITY); | ||
// assert_eq!(format(f64::NEG_INFINITY).unwrap_err(), ERR_INFINITY); | ||
// assert_eq!(format(f64::NAN).unwrap_err(), ERR_NAN); | ||
// assert_eq!(format(f32::INFINITY).unwrap_err(), ERR_INFINITY); | ||
// assert_eq!(format(f32::NEG_INFINITY).unwrap_err(), ERR_INFINITY); | ||
// assert_eq!(format(f32::NAN).unwrap_err(), ERR_NAN); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters