Convert float64 to hexadecimal in Rust - rust

I would like to know how to convert a float64 (or float32) to a corresponding binary/hexadecimal format. It would be great to be able to specify endianness as well (prefer to print it in little-endian format).
Linked post: How to convert hex string to a float in Rust?
Thanks!

Use f32::to_be_bytes, f32::to_le_bytes, or f32::to_ne_bytes (depending on the desired endianness) and then format the resulting elements of the array:
let float: f32 = 123.45;
let bytes = float.to_le_bytes();
let hex = format!("{:02X}{:02X}{:02X}{:02X}", bytes[0], bytes[1], bytes[2], bytes[3]);
assert_eq!(hex, "66E6F642");
No need for the unsafe and dangerous transmute.
Rust Playground Link

It's just the inverse of the operations from the answer to the question you linked:
fn main() {
// Hex string to 4-bytes, aka. u32
let float: f32 = 18.9;
let bytes = unsafe { std::mem::transmute::<f32, u32>(float) };
let hex = format!("{:x}", bytes);
// Print 41973333
println!("{}", hex);
}
Rust Playground link
Call .from_be(), .from_le() or .swap_bytes() on the u32 value (bytes) before formatting to alter the byte order. Change from f32 and u32 to f64 and u64 for larger data types.
Similarly, the other answer to that question (using f32.from_bits) has a direct inverse in f32.to_bits (though those functions are still marked as unstable).

Related

Copy a slice of i32 pixels into an [u8] slice

How to copy a row of pixels in an i32 slice into an existing slice of pixels in an [u8] slice ?
Both slices are in the same memory layout (i.e. RGBA) but I don't know the unsafe syntax to copy one efficiently into the other. In C it would just be a memcpy().
You can flat_map the byte representation of each i32 into a Vec<u8>:
fn main() {
let pixels: &[i32] = &[-16776961, 16711935, 65535, -1];
let bytes: Vec<u8> = pixels
.iter()
.flat_map(|e| e.to_ne_bytes())
.collect();
println!("{bytes:?}");
}
There are different ways to handle the endianess of the system, I left to_ne_bytes to preserve the native order, but there are also to_le_bytes and to_be_bytes if that is something that needs to be controlled.
Alternatively, if you know the size of your pixel buffer ahead of time, you can use an unsafe transmute:
const BUF_LEN: usize = 4; // this is your buffer length
fn main() {
let pixels: [i32; BUF_LEN] = [-16776961, 16711935, 65535, -1];
let bytes = unsafe {
std::mem::transmute::<[i32; BUF_LEN], [u8; BUF_LEN * 4]>(pixels)
};
println!("{bytes:?}");
}
Assuming that you in fact do not need any byte reordering, the bytemuck library is the tool to use here, as it allows you to write the i32 to u8 reinterpretation without needing to consider safety (because bytemuck has checked it for you).
Specifically, bytemuck::cast_slice() will allow converting &[i32] to &[u8].
(In general, the function may panic if there is an alignment or size problem, but there never can be such a problem when converting to u8 or any other one-byte type.)

How to convert a very large decimal string to hexadecimal?

let hex = "100000000000000000".as_bytes().to_hex();
// hex == "313030303030303030303030303030303030"
println!("{:x}", 100000000000000000000000u64);
// literal out of range for u64
How can I got that value?
In Python, I would just call hex(100000000000000000000000) and I get '0x152d02c7e14af6800000'.
to_hex() comes from the hex crate.
One needs to be aware of the range of representable values for different numeric types in Rust. In this particular case, the value exceeds the limits of an u64, but the u128 type accommodates the value. The following code outputs the same value as the example in Python:
fn main() {
let my_string = "100000000000000000000000".to_string(); // `parse()` works with `&str` and `String`!
let my_int = my_string.parse::<u128>().unwrap();
let my_hex = format!("{:X}", my_int);
println!("{}", my_hex);
}
Checked with the Rust Playground:
152D02C7E14AF6800000
An explicit usage of arbitrary precision arithmetic is required in the general case. A few suggestions from What's the best crate for arbitrary precision arithmetic in Rust? on Reddit:
num_bigint works on stable and does not have unsafe code.
ramp uses unsafe and does not work on stable Rust, but it is faster.
rust-gmp and rug bind to the state-of-the-art bigint implementation in C (GMP). They are the fastest and have the most features. You probably want to use one of those.

Can a BigInteger be truncated to an i32 in Rust?

In Java, intValue() gives back a truncated portion of the BigInteger instance. I wrote a similar program in Rust but it appears not to truncate:
extern crate num;
use num::bigint::{BigInt, RandBigInt};
use num::ToPrimitive;
fn main() {
println!("Hello, world!");
truncate_num(
BigInt::parse_bytes(b"423445324324324324234324", 10).unwrap(),
BigInt::parse_bytes(b"22447", 10).unwrap(),
);
}
fn truncate_num(num1: BigInt, num2: BigInt) -> i32 {
println!("Truncation of {} is {:?}.", num1, num1.to_i32());
println!("Truncation of {} is {:?}.", num2, num2.to_i32());
return 0;
}
The output I get from this is
Hello, world!
Truncation of 423445324324324324234324 is None.
Truncation of 22447 is Some(22447).
How can I achieve this in Rust? Should I try a conversion to String and then truncate manually? This would be my last resort.
Java's intValue() returns the lowest 32 bits of the integer. This could be done by a bitwise-AND operation x & 0xffffffff. A BigInt in Rust doesn't support bitwise manipulation, but you could first convert it to a BigUint which supports such operations.
fn truncate_biguint_to_u32(a: &BigUint) -> u32 {
use std::u32;
let mask = BigUint::from(u32::MAX);
(a & mask).to_u32().unwrap()
}
Converting BigInt to BigUint will be successful only when it is not negative. If the BigInt is negative (-x), we could find the lowest 32 bits of its absolute value (x), then negate the result.
fn truncate_bigint_to_u32(a: &BigInt) -> u32 {
use num_traits::Signed;
let was_negative = a.is_negative();
let abs = a.abs().to_biguint().unwrap();
let mut truncated = truncate_biguint_to_u32(&abs);
if was_negative {
truncated.wrapping_neg()
} else {
truncated
}
}
Demo
You may use truncate_bigint_to_u32(a) as i32 if you need a signed number.
There is also a to_signed_bytes_le() method with which you could extract the bytes and decode that into a primitive integer directly:
fn truncate_bigint_to_u32_slow(a: &BigInt) -> u32 {
let mut bytes = a.to_signed_bytes_le();
bytes.resize(4, 0);
bytes[0] as u32 | (bytes[1] as u32) << 8 | (bytes[2] as u32) << 16 | (bytes[3] as u32) << 24
}
This method is extremely slow compared to the above methods and I don't recommend using it.
There's no natural truncation of a big integer into a smaller one. Either it fits or you have to decide what value you want.
You could do this:
println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(-1));
or
println!("Truncation of {} is {:?}.", num1, num1.to_i32().unwrap_or(std::i32::MAX));
but your application logic should probably dictate what's the desired behavior when the returned option contains no value.

How to convert hex string to a float in Rust?

What's the most straightforward way to convert a hex string into a float? (without using 3rd party crates).
Does Rust provide some equivalent to Python's struct.unpack('!f', bytes.fromhex('41973333'))
See this question for Python & Java, mentioning for reference.
This is quite easy without external crates:
fn main() {
// Hex string to 4-bytes, aka. u32
let bytes = u32::from_str_radix("41973333", 16).unwrap();
// Reinterpret 4-bytes as f32:
let float = unsafe { std::mem::transmute::<u32, f32>(bytes) };
// Print 18.9
println!("{}", float);
}
Playground link.
There's f32::from_bits which performs the transmute in safe code. Note that transmuting is not the same as struct.unpack, since struct.unpack lets you specify endianness and has a well-defined IEEE representation.

Creating a string from Vec<char> [duplicate]

This question already has answers here:
How to convert Vec<char> to a string
(2 answers)
Closed 6 years ago.
I've got a Vec<char> that I need to turn into a &str or String, but I'm unsure of the best way to do this. I've looked around and every resource I've found seems to be out-dated in some way. The answers in this question don't seem to be applicable for the newest build.
I'm using the nightly for 2015-3-19
The iterator based approach with .collect should work, after updating for language changes:
char_vector.iter().cloned().collect::<String>();
(I've chosen to replace .map(|c| *c) with .cloned() but either works.)
If your vector can be consumed, you can also use into_iter to avoid the clone
fn main() {
let char_vector = vec!['h', 'e', 'l', 'l', 'o'];
let str: String = char_vector.into_iter().collect();
println!("{}", str);
}
You can convert the Vec into a String without doing any allocations. It requires quite some unsafe code though:
#![feature(raw, unicode)]
use std::raw::Repr;
use std::slice::from_raw_parts_mut;
fn inplace_to_string(v: Vec<char>) -> String {
unsafe {
let mut i = 0;
{
let ch_v = &v[..];
let r = ch_v.repr();
let p: &mut [u8] = from_raw_parts_mut(r.data as *mut u8, r.len*4);
for ch in ch_v {
i += ch.encode_utf8(&mut p[i..i+4]).unwrap();
}
}
let p = v.as_ptr();
let cap = v.capacity()*4;
std::mem::forget(v);
let v = Vec::from_raw_parts(p as *mut u8, i, cap);
String::from_utf8_unchecked(v)
}
}
fn main() {
let char_vector = vec!['h', 'ä', 'l', 'l', 'ö'];
let str: String = char_vector.iter().cloned().collect();
let str2 = inplace_to_string(char_vector);
println!("{}", str);
println!("{}", str2);
}
PlayPen
Detailed Explanation
This creates a mutable u8 slice and a char slice simultaneously to the same buffer (breaking all Rust guarantees). Note that the u8 slice is four times as large as the char slice, since char always takes up 4 bytes.
let ch_v = &v[..];
let r = ch_v.repr();
let v: &mut [u8] = from_raw_parts_mut(r.data as *mut u8, r.len*4);
We need that to iterate over the unicode chars and replace them by their utf8 encoded counterpart. Since utf8 is always shorter or the same length as unicode, we can guarantee that we never overwrite any part we haven't read yet.
for ch in ch_v {
i += ch.encode_utf8(&mut v[i..i+4]).unwrap();
}
Since a char is always unicode and our buffer is always exactly 4 bytes (which is the maximum number of bytes a utf8 encoded unicode char will need), we can encode our chars to utf8 without checking if it worked (it will always work). The encode_utf8 function returns the length of the utf8 representation. Our index i is the location of the last written utf8 char.
Finally we need to do some cleaning up. Our vector is still of type Vec<char>. We get all the info we need (Pointer to the heap allocated array and the capacity)
let p = v.as_ptr();
let cap = v.capacity()*4;
Then we release the previous vector from all obligations like freeing memory.
std::mem::forget(v);
and finally recreate the u8 vector with correct length and capacity, and directly turn it into a String. The conversion to String does not need to be checked, as we already know the utf8 is correct, since the original Vec<char> could only contain correct unicode chars.
let v = Vec::from_raw_parts(p as *mut u8, i, cap);
String::from_utf8_unchecked(v)

Resources