How to decode and encode a float in Rust?

南笙酒味 提交于 2019-12-11 06:15:51

问题


I want to decode, store and encode a float in Rust. I know about num::Float::integer_decode() but I'd rather not lose any precision. That is, unless the format I encode into is smaller than the format I encode from of course.


回答1:


Interpret the floating point bits as an integer and print out the value as hex:

use std::mem;

fn main() {
    let a_third: f64 = 1.0 / 3.0;

    let as_int: u64 = unsafe { mem::transmute(a_third) };
    println!("{}", as_int);

    let as_string = format!("{:016x}", as_int);
    println!("{}", as_string);

    let back_to_int = u64::from_str_radix(&as_string, 16).expect("Not an integer");
    println!("{}", back_to_int);

    let back_to_float: f64 = unsafe { mem::transmute(back_to_int) };
    println!("{}", back_to_float);

    assert_eq!(back_to_float, a_third);
}



回答2:


What's wrong with integer_decode()? It is lossless and works for finite numbers as well as NaN and infinities:

use std::mem;

fn integer_decode(val: f64) -> (u64, i16, i8) {
    let bits: u64 = unsafe { mem::transmute(val) };
    let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
    let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
    let mantissa = if exponent == 0 {
        (bits & 0xfffffffffffff) << 1
    } else {
        (bits & 0xfffffffffffff) | 0x10000000000000
    };

    exponent -= 1023 + 52;
    (mantissa, exponent, sign)
}

fn main() {
    println!("{:?}", integer_decode(std::f64::NAN));
    println!("{:?}", integer_decode(std::f64::INFINITY));
    println!("{:?}", integer_decode(std::f64::NEG_INFINITY));
}



回答3:


If you don't intend to transfer serialized data between machines or you're certain that float representation is the same on all platforms you target, you can store byte representation of the number:

use std::io::{Read, Write};

fn main() {
  {
    let num: f64 = 1.0 / 3.0;
    let bytes: [u8; 8] = unsafe { std::mem::transmute(num) };
    let mut file = std::fs::File::create("/tmp/1").unwrap();
    file.write_all(&bytes).unwrap();
  }
  {
    let mut file = std::fs::File::open("/tmp/1").unwrap();
    let mut bytes: [u8; 8] = unsafe { std::mem::uninitialized() };
    file.read_exact(&mut bytes).unwrap();
    let num: f64 = unsafe { std::mem::transmute(bytes) };
    println!("result: {}", num);
  }
}

You can also use existing serialization framework, like serde. If you don't want the entire framework and just want to serialize floats, you can use dtoa (it's used by serde_json), although I'm not sure if it provides strong precision guarantees.



来源:https://stackoverflow.com/questions/40030551/how-to-decode-and-encode-a-float-in-rust

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!