
Code: Select all
Prompt:
Rust code to convert an i64 (8-byte signed integer) to a little-endian representation
Response:
Here's a simple Rust function to convert an i64 to its little-endian byte representation:
```rust
fn to_le_bytes(value: i64) -> [u8; 8] {
value.to_le_bytes()
}
```
...
Didn't take long, a couple of minutes, but the llm is on a strix halo[/quote]
Right answer, but wrong question! I was aware of to_le_bytes, and I'd hope that any self-respecting (?) AI would be too. The bit of the requirement that makes it harder is to use the fewest bytes, so say 127 takes one byte, but 128 takes 2, 32767 also takes 2, but 32768 takes 3, etc. (and similarly but not identically for negative numbers; the difference is what requires some care).
My installed AI's solution was to iterate over the max/min numbers (expressed as a bit mask with shifts, which is a bit involved but logical) for each number of bytes, 1-8, and compare the number in question.
What I think is optimal is to locate the number's binary representation's first 1 from the left in +ve, first 0 in -ve. The preceding bits are all just sign bits, and we need retain at least one, but not more that 7 of them, so you can directly calculate how many of the to_le_bytes are needed. The first part of that, locating the first 1/0 is equivalent to counting the leading 0's/1s, which are the Rust method leading_zeros and leading_ones. The useful feature is that on modern CPUs, that's a BSR instruction on a register, which is therefore pretty quick, followed by a division by 8 (a.k.a. >>3). Hence me suggesting it to the AI. What I didn't check is whether the AI was aware of said methods (I think they're relatively recent introductions to Rust - trouble with moving targets :-( ), perhaps not.
I kind of expect it to respond with the rust version, given the broadly ambiguous prompt.Goverp wrote:Right answer, but wrong question! I was aware of to_le_bytes, and I'd hope that any self-respecting (?) AI would be too.
Code: Select all
/// Convert an i64 to its little-endian byte representation.
/// Most efficient implementation using bitwise operations.
#[inline]
pub fn i64_to_le(value: i64) -> [u8; 8] {
// Extract each byte using bitwise operations
// This is more efficient than loops or arithmetic for fixed-size integers
[
(value as u8), // bits 0-7
((value >> 8) as u8), // bits 8-15
((value >> 16) as u8), // bits 16-23
((value >> 24) as u8), // bits 24-31
((value >> 32) as u8), // bits 32-39
((value >> 40) as u8), // bits 40-47
((value >> 48) as u8), // bits 48-55
((value >> 56) as u8), // bits 56-63
]
}
/// Alternative implementation using a union for zero-cost abstraction.
/// This is also highly efficient but requires unsafe code.
#[inline]
pub fn i64_to_le_union(value: i64) -> [u8; 8] {
// On little-endian systems (most modern CPUs), this is essentially free
// On big-endian systems, this would still be efficient with just a copy
// Note: This relies on platform endianness at runtime
unsafe {
let mut result = [0u8; 8];
std::ptr::copy_nonoverlapping(
&value as *const i64 as *const u8,
result.as_mut_ptr(),
8,
);
result
}
}If I might add a little bit on thisAnon-E-moose wrote:The more I play with llms the more I realize that the prompt is extremely important, not just for directions of what to do,
but more importantly, directions of what not to do.

My prompt was:Anon-E-moose wrote:I kind of expect it to respond with the rust version, given the broadly ambiguous prompt.Goverp wrote:Right answer, but wrong question! I was aware of to_le_bytes, and I'd hope that any self-respecting (?) AI would be too.
Because the prompt was "Rust code to convert an i64 (8-byte signed integer) to a little-endian representation."
...
The more I play with llms the more I realize that the prompt is extremely important, not just for directions of what to do,
but more importantly, directions of what not to do.
later amended toWrite Rust code to convert an i64 (8-byte signed integer) to a little-endian representation using the fewest bytes
Note the "fewest bytes", which rules out naive use of to_le_bytes.Using the Rust functions leading_zeros and leading_ones, write code to convert an i64 (8-byte signed integer) to a little-endian representation using the fewest bytes
Code: Select all
pub fn to_bytes(number: i64) -> Vec<u8> {
if number == 0 {
return Vec::new();
}
for n in 1..=8 {
let min_val = -(1i64 << (8 * (n - 1)));
let max_val = (1i64 << (8 * (n - 1))) - 1;
if number >= min_val && number <= max_val {
let num = number as u64;
let mut bytes = Vec::with_capacity(n as usize);
for i in 0..n {
let byte = ((num >> (i * 8)) & 0xFF) as u8;
bytes.push(byte);
}
return bytes;
}
}
Vec::new()
}
Using the Rust functions leading_zeros and leading_ones, write code to convert an i64 (8-byte signed integer) to a little-endian representation using the fewest bytes, do not use built in functions, write your own.
Code: Select all
/// Convert an i64 to its minimal little-endian representation.
///
/// Uses leading_zeros/leading_ones to determine byte count.
/// Manually extracts bytes - no built-in byte conversion functions.
///
/// For positive numbers: MSB of last byte must be 0
/// For negative numbers (two's complement): MSB of last byte must be 1
pub fn to_le_min(value: i64) -> Vec<u8> {
if value == 0 {
return Vec::new();
}
// Extract raw little-endian bytes manually (8 bytes for i64)
let mut raw_bytes = [0u8; 8];
for i in 0..8 {
raw_bytes[i] = ((value >> (i * 8)) & 0xFF) as u8;
}
if value >= 0 {
// Positive: use leading_zeros to determine significant bits
let leading = value.leading_zeros() as usize;
let bits_needed = 64 - leading;
let mut bytes_needed = (bits_needed + 7) / 8;
// If last byte's MSB would be 1, we need a zero-padding byte
if (bits_needed % 8) == 0 {
bytes_needed += 1;
}
// Clamp to max 8 bytes
let len = bytes_needed.min(8);
raw_bytes[0..len].to_vec()
} else {
// Negative: use two's complement sign extension logic
// Count leading ones (sign extension bits)
let leading_ones = value.leading_ones() as usize;
// The significant bits are 64 - leading_ones
let bits_needed = 64 - leading_ones;
// Calculate bytes needed
let mut bytes_needed = (bits_needed + 7) / 8;
// Need at least 1 byte for any negative number
if bytes_needed == 0 {
bytes_needed = 1;
}
// For negative numbers, if significant bits don't reach MSB of last byte,
// we need sign extension (0xFF) byte
if bits_needed > 0 && (bits_needed % 8) == 0 {
bytes_needed += 1;
}
// Clamp to max 8 bytes
let len = bytes_needed.min(8);
raw_bytes[0..len].to_vec()
}
}