Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Idiomatically Test for Overflow when Shifting Left (<<) in Rust?

For most operators that might overflow, Rust provides a checked version. For example, to test if an addition overflows one could use checked_add:

match 255u8.checked_add(1) {
    Some(_) => println!("no overflow"),
    None => println!("overflow!"),
}

This prints "overflow!". There is also a checked_shl, but according to the documentation it only checks if the shift is larger than or equal to the number of bits in self. That means that while this:

match 255u8.checked_shl(8) {
    Some(val) => println!("{}", val),
    None => println!("overflow!"),
}

is caught and prints "overflow!", This:

match 255u8.checked_shl(7) {
    Some(val) => println!("{}", val),
    None => println!("overflow!"),
}

simply prints 128, clearly not catching the overflow. What is the correct way to check for any kind of overflow when shifting left?

like image 755
chuck Avatar asked Aug 22 '20 15:08

chuck


People also ask

How to handle overflows in rust?

Check these out. Which one does * correspond to? Rust provides the following methods to handle overflows: checked_mul, saturating_mul, wrapping_mul, overflowing_mul. (other operations are supported as well) So your example can be rewritten as: let z = match x.checked_mul (y) { Some (val) => val, None => { ...

What is “shift left” testing?

The “shift left” testing movement is about pushing testing toward the early stages of software development. By testing early and often, a project can reduce the number of bugs and increase the quality of the code. The goal is to not find any critical bugs during the deployment phase that require code patching.

What is the rule for overflow in math?

There can be overflow only if signs of two numbers are same, and sign of sum is opposite to the signs of numbers. 1) Calculate sum 2) If both numbers are positive and sum is negative then return -1 Else If both numbers are negative and sum is positive then return -1 Else return 0

How to check for integer overflow?

Check for Integer Overflow. Write a “C” function, int addOvf (int* result, int a, int b) If there is no overflow, the function places the resultant = sum a+b in “result” and returns 0. Otherwise it returns -1.


1 Answers

I'm not aware of any idiomatic way of doing this, but something like implementing your own trait would work: Playground

The algorithm is basically to check if there are not fewer leading zeros in the number than the shift size

#![feature(bool_to_option)]

trait LossCheckedShift {
    fn loss_checked_shl(self, rhs: u32) -> Option<Self> 
        where Self: std::marker::Sized;
}

impl LossCheckedShift for u8 {
    fn loss_checked_shl(self, rhs: u32) -> Option<Self> {
        (rhs <= self.leading_zeros()).then_some(self << rhs)
        // in stable Rust
        // if rhs <= self.leading_zeros() { Some(self << rhs) }
        // else { None }
    }
}

fn main() {
    match 255u8.loss_checked_shl(7) {
        Some(val) => println!("{}", val),
        None => println!("overflow!"), // <--
    } 
    
    match 127u8.loss_checked_shl(1) {
        Some(val) => println!("{}", val), // <--
        None => println!("overflow!"),
    }
    match 127u8.loss_checked_shl(2) {
        Some(val) => println!("{}", val),
        None => println!("overflow!"), // <--
    }
}
like image 67
Alexey Larionov Avatar answered Sep 19 '22 22:09

Alexey Larionov