Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #![feature(bench_black_box)]
- #![feature(test)]
- extern crate test;
- use test::Bencher;
- pub struct Duration {
- secs: u64,
- nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
- }
- pub struct FromSecsError {
- kind: FromSecsErrorKind,
- }
- enum FromSecsErrorKind {
- // Value is not a finite value (either infinity or NaN).
- NonFinite,
- // Value is too large to store in a `Duration`.
- Overflow,
- // Value is less than `0.0`.
- Negative,
- }
- pub fn try_from_secs_f64_libm(secs: f64) -> Result<Duration, FromSecsError> {
- const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
- const NANOS_PER_SEC: u32 = 1_000_000_000;
- let nanos = secs * (NANOS_PER_SEC as f64);
- if !nanos.is_finite() {
- Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
- } else if nanos >= MAX_NANOS_F64 {
- Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
- } else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Negative })
- } else {
- let nanos = nanos as u128;
- Ok(Duration {
- secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
- nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
- })
- }
- }
- pub fn try_from_secs_f64_frac(secs: f64) -> Result<Duration, FromSecsError> {
- const NANOS_PER_SEC: u32 = 1_000_000_000;
- const FRACT_BITS: u64 = 52;
- const FRACT_MASK: u64 = (1 << FRACT_BITS) - 1;
- const EXP_BITS: u64 = 11;
- const EXP_MASK: u64 = (1 << EXP_BITS) - 1;
- const DIV: u128 = 1u128 << FRACT_BITS;
- if secs.is_sign_negative() {
- return Err(FromSecsError { kind: FromSecsErrorKind::Negative });
- } else if !secs.is_finite() {
- return Err(FromSecsError { kind: FromSecsErrorKind::NonFinite });
- }
- let bits = secs.to_bits();
- let fract = (bits & FRACT_MASK) | (FRACT_MASK + 1);
- let exp = ((bits >> FRACT_BITS) & EXP_MASK) as i32 - 1023;
- let (secs, nanos) = match exp {
- -1023..=-33 => (0, 0),
- -32..=-1 => {
- let t = fract >> exp.abs();
- let nanos = (NANOS_PER_SEC as u128 * (t as u128)) / DIV;
- (0, nanos as u32)
- }
- 0..=51 => {
- let secs = fract >> (FRACT_BITS - exp as u64);
- let t = (fract << exp) & FRACT_MASK;
- let nanos = (NANOS_PER_SEC as u128 * (t as u128)) / DIV;
- (secs, nanos as u32)
- }
- 52..=63 => {
- let secs = fract << (exp as u64 - FRACT_BITS);
- (secs, 0)
- }
- _ => return Err(FromSecsError { kind: FromSecsErrorKind::Overflow }),
- };
- Ok(Duration { secs, nanos })
- }
- pub fn try_from_secs_f64_frac_reordered(secs: f64) -> Result<Duration, FromSecsError> {
- const NANOS_PER_SEC: u32 = 1_000_000_000;
- const FRACT_BITS: u64 = 52;
- const FRACT_MASK: u64 = (1 << FRACT_BITS) - 1;
- const EXP_BITS: u64 = 11;
- const EXP_MASK: u64 = (1 << EXP_BITS) - 1;
- const DIV: u128 = 1u128 << FRACT_BITS;
- if secs.is_sign_negative() {
- return Err(FromSecsError { kind: FromSecsErrorKind::Negative });
- } else if !secs.is_finite() {
- return Err(FromSecsError { kind: FromSecsErrorKind::NonFinite });
- }
- let bits = secs.to_bits();
- let fract = (bits & FRACT_MASK) | (FRACT_MASK + 1);
- let exp = ((bits >> FRACT_BITS) & EXP_MASK) as i32 - 1023;
- let (secs, nanos) = match exp {
- 0..=51 => {
- let secs = fract >> (FRACT_BITS - exp as u64);
- let t = (fract << exp) & FRACT_MASK;
- let nanos = (NANOS_PER_SEC as u128 * (t as u128)) / DIV;
- (secs, nanos as u32)
- }
- -32..=-1 => {
- let t = fract >> exp.abs();
- let nanos = (NANOS_PER_SEC as u128 * (t as u128)) / DIV;
- (0, nanos as u32)
- }
- -1023..=-33 => (0, 0),
- 52..=63 => {
- let secs = fract << (exp as u64 - FRACT_BITS);
- (secs, 0)
- }
- _ => return Err(FromSecsError { kind: FromSecsErrorKind::Overflow }),
- };
- Ok(Duration { secs, nanos })
- }
- macro_rules! bench {
- ($name:ident, $num:expr) => {
- mod $name {
- bench!($num);
- }
- };
- ($num:expr) => {
- #[bench]
- fn try_from_secs_f64_libm(b: &mut test::Bencher) {
- b.iter(|| crate::try_from_secs_f64_libm(std::hint::black_box($num)));
- }
- #[bench]
- fn try_from_secs_f64_frac(b: &mut test::Bencher) {
- b.iter(|| crate::try_from_secs_f64_frac(std::hint::black_box($num)));
- }
- #[bench]
- fn try_from_secs_f64_frac_reordered(b: &mut test::Bencher) {
- b.iter(|| crate::try_from_secs_f64_frac_reordered(std::hint::black_box($num)));
- }
- };
- }
- bench!(negative, -500.0);
- bench!(zero, 0.0);
- bench!(one, 1.0);
- bench!(megapi, 3.14e5);
- bench!(thirteen, 30.0);
- bench!(small, 8000.0);
- bench!(medium, 85623.8745);
- bench!(big, 99995412.2554122554);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement