How do you set, clear and toggle a single bit in Rust? - rust

How do I set, clear and toggle a bit in Rust?

Like many other languages, the bitwise operators & (bitwise AND), | (bitwise OR), ^ (bitwise XOR) exist:
fn main() {
let mut byte: u8 = 0b0000_0000;
byte |= 0b0000_1000; // Set a bit
println!("0b{:08b}", byte);
byte &= 0b1111_0111; // Unset a bit
println!("0b{:08b}", byte);
byte ^= 0b0000_1000; // Toggle a bit
println!("0b{:08b}", byte);
}
The main difference from other languages is in bitwise NOT, which uses ! instead of ~:
fn main() {
let mut byte: u8 = 0b0000_0000;
byte = !byte; // Flip all bits
println!("0b{:08b}", byte);
}
You can also shift bits left or right:
fn main() {
let mut byte: u8 = 0b0000_1000;
byte <<= 1; // shift left one bit
println!("0b{:08b}", byte);
byte >>= 1; // shift right one bit
println!("0b{:08b}", byte);
}
There are many other conceptual things that ultimately do bit-level manipulation that are not expressed with operators. Check out the documentation for an integer for examples. One interesting example is leading_zeros. Here is how to rotate by a certain number of bits:
fn main() {
let mut byte: u8 = 0b1000_0000;
byte = byte.rotate_left(1); // rotate left one bit
println!("0b{:08b}", byte);
byte = byte.rotate_right(1); // rotate right one bit
println!("0b{:08b}", byte);
}
The book has some more information

Rust has both bit-twiddling operators and binary format printing (very helpful for debugging):
fn bit_twiddling(original: u8, bit: u8) {
let mask = 1 << bit;
println!(
"Original: {:b}, Set: {:b}, Cleared: {:b}, Toggled: {:b}",
original,
original | mask,
original & !mask,
original ^ mask
);
}
fn main() {
bit_twiddling(0, 3);
bit_twiddling(8, 3);
}
It also has the compound assignment variants (|=, &= and ^=).
The book has some more information

Additionally, I'd like to add the following use case: If you have a bitfield like 0b10001000 and you want to update bit 3 in any case to true or false, you can do it like this:
const SHIFT: u8 = 3;
let set_bit_3 = false;
let bits = 0b10001000;
let bits = bits & !(1 << SHIFT) | (u16::from(set_bit_3) << SHIFT);

Related

get byte offset after first char of str in rust

In rust, I want to get the byte offset immediately after of the first character of a str.
Rust Playground
fn main() {
let s: &str = "⚀⚁";
// char is 4 bytes, right??? (not always when in a str)
let offset: usize = 4;
let s1: &str = &s[offset..];
eprintln!("s1 {:?}", s1);
}
The program expectedly crashes with:
thread 'main' panicked at 'byte index 4 is not a char boundary; it is inside '⚁' (bytes 3..6) of `⚀⚁`'
How can find the byte offset for the second char '⚁' ?
Bonus if this can be done safely and without std.
Related:
How to get the byte offset between &str
How to find the starting offset of a string slice of another string?
A char is a 32-bit integer (a unicode scalar value), but individual characters inside a str are variable width UTF-8, as small as a single 8-bit byte.
You can iterate through the characters of the str and their boundaries using str::char_indices, and your code would look like this:
fn main() {
let s: &str = "⚀⚁";
let (offset, _) = s.char_indices().nth(1).unwrap();
dbg!(offset); // 3
let s1: &str = &s[offset..];
eprintln!("s1 {:?}", s1); // s1 "⚁"
}

How do I split a 16-bit value into two 8-bit values?

I have u16 value and want to convert it into two u8 values to put it into u8 array, the same as described here.
0000000000000011 -> 00000000 and 00000011
How would I do that in a convenient way?
Putting the answers provided by #apilat and #Anton into code:
Bit Shifting - verbose style
This can be accomplished in a couple of different ways. I actually think that bit shifting is a little clearer, as no thought needs to be given to whether I need to worry about endianness.
Spelling out each:
fn shift_verbose_split_u16(short_16: u16) -> [u8; 2] {
let high_byte: u8 = (short_16 >> 8) as u8;
let low_byte: u8 = (short_16 & 0xff) as u8;
return [high_byte, low_byte];
}
Bit Shifting - idiomatic style
The above code can be reduced to a one-line function:
fn shift_idiomatic_split_u16(short_16: u16) -> [u8; 2] {
[(short_16 >> 8) as u8, (short_16 & 0xff) as u8]
}
Using to_be_bytes()
Using to_be_bytes() certainly is the simplest solution. Using this solution, you have to realize that you really want to use the big-endian call, regardless of the underlying cpu's architecture:
let [high, low] = short_16.to_be_bytes();
Grouping the code into one file:
fn main() {
let short_16: u16 = 0x3f23;
// verbose bit shifting
let [high, low] = shift_verbose_split_u16(short_16);
assert_eq!(high, 0x3f);
assert_eq!(low, 0x23);
// idiomatic bit shifting
let [high, low] = shift_idiomatic_split_u16(short_16);
assert_eq!(high, 0x3f);
assert_eq!(low, 0x23);
let [high, low] = short_16.to_be_bytes();
assert_eq!(high, 0x3f);
assert_eq!(low, 0x23);
println!("High: {:#0x?}, Low: {:#0x?}", high, low);
}
fn shift_verbose_split_u16(short_16: u16) -> [u8; 2] {
let high_byte: u8 = (short_16 >> 8) as u8;
let low_byte: u8 = (short_16 & 0xff) as u8;
return [high_byte, low_byte];
}
fn shift_idiomatic_split_u16(short_16: u16) -> [u8; 2] {
[(short_16 >> 8) as u8, (short_16 & 0xff) as u8]
}
Output:
High: 0x3f, Low: 0x23

Insert a bit in an 8-bit integer

I have a 5-bit u8, let's say 0b10101. I want to insert three bits, all ones, into positions 1, 2, and 4, to get: ii1i0101, i.e., 11110101. I want to accomplish this in three function calls, meaning that the function should take the index as one of the parameters and insert a single bit in that position.
I've come across this question, however, the answers on that page did not work for me. For example, the answer with the least upvotes panics when implemented, while others do not give the correct result.
fn insert_at(x: u8, index: u8, bit: u8) -> u8 {
let mask = (1 << (8 - index + 1)) - 1;
(x & !mask) | (bit << (8 - index)) | ((x & mask) >> 1)
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::*;
#[rstest(
input, index, expected,
case(0b10101, 1, 0b110101),
)]
fn test_bla(input: u8, index: u8, expected: u8) {
let result = insert_at(input, index, 1);
assert_eq!(result, expected);
}
}
thread 'tests::test_bla::case_1' panicked at 'attempt to shift left with overflow'
I've made a few assumptions (and a modification) to make the semantics of your question a bit more concrete:
The result of the operation must fit in 8 bits; if it does not, no value is returned.
index 0 (rather than index 1) refers to the position to the left of the most significant set bit.
A bit inserted in any index > 0 shifts all more significant set bits to the left by 1.
A working implementation (playground link):
fn insert_at(x: u8, index: u8, bit: u8) -> Option<u8> {
if bit != 0 && bit != 1 {
return None;
}
// most significant set bit, from right
// 0b00010101
// 87654321
let msb = 8 - x.leading_zeros() as u8;
if index >= msb {
// the new bit is past the LSB
return None;
}
// an index of 0 means insert as the new MSB (if it fits).
// insert is the absolute index of the inserted bit.
let insert = msb - index;
if insert == 8 {
// the new bit is out of u8 range.
// 0b_11111111
// ^ trying to insert here
return None;
}
let mask = (1 << insert) - 1;
Some((x & !mask) << 1 | (bit << insert) | (x & mask))
}
The reason your implementation panics is that Rust's left-shift operation is checked: if any bits would be shifted off the left side of the integer, the check fails. The main reasoning for this is that different platforms have different behavior in this case.
Rust also provides arithmetic operations with specified behavior in these cases, such as overflowing_shl() and wrapping_shl().

How to raise a number to a power?

I was trying to raise an integer to a power using the caret operator (^), but I am getting surprising results, e.g.:
assert_eq!(2^10, 8);
How can I perform exponentiation in Rust?
Rust provides exponentiation via methods pow and checked_pow. The latter
guards against overflows. Thus, to raise 2 to the power of 10, do:
let base: i32 = 2; // an explicit type is required
assert_eq!(base.pow(10), 1024);
The caret operator ^ is not used for exponentiation, it's the bitwise XOR
operator.
Here is the simplest method which you can use:
let a = 2; // Can also explicitly define type i.e. i32
let a = i32::pow(a, 10);
It will output "2 raised to the power of 10", i.e.:
1024
For integers:
fn main() {
let n = u32::pow(2, 10);
println!("{}", n == 1024);
}
For floats:
fn main() {
// example 1
let f = f32::powf(2.0, 10.0);
// example 2
let g = f32::powi(2.0, 10);
// print
println!("{}", f == 1024.0 && g == 1024.0);
}
or, since your base is 2, you can also use shift:
fn main() {
let n = 2 << 9;
println!("{}", n == 1024);
}
https://doc.rust-lang.org/std/primitive.f32.html#method.powf
https://doc.rust-lang.org/std/primitive.f32.html#method.powi
https://doc.rust-lang.org/std/primitive.u32.html#method.pow
I was trying the same thing as the OP. Thanks to the other answer authors.
Here's a variation that works for me:
let n = 2u32.pow(10);
This uses a literal unsigned 32 bit integer to set the type and base, then calls the pow() function on it.
Bit shifting is a good way to do this particular case:
assert_eq!(1 << 10, 1024);

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.

Resources