Rust-盘一下数字相关的函数(二)

上期内容:Rust-盘一下数字相关的

上一次盘的是有符号整数的相关函数实现,包括一些位运算、几个科学计算方法等等,这回盘一下计算检测溢出的几个方法,以及其中的区别。

以下均处于int_impl宏内,其中部分方法与uint_impl实现有区别。

overflowing_* 系列:

const fn overflowing_add(self, rhs: Self) -> (Self, bool) 加法,正常二进制加法运算,如果存在溢出返回的元组中的bool为true;两个加数与和的类型必须相同。

let num:i8 = std::i8::MAX;
println!("{:?}", a.overflowing_add(2));
-----
(-127, true)

const fn overflowing_sub(self, rhs: Self) -> (Self, bool) 带溢出检测的减法运算。

const fn overflowing_mul(self, rhs: Self) -> (Self, bool) 带溢出检测的乘法。

const fn overflowing_div(self, rhs: Self) -> (Self, bool) 带溢出检测的除法,rhs是除数,self是被除数。当rhs为0时程序会panic。仅当被除数是有符号类型内最小值并且除数rhs是-1时会发生溢出,其余均不会溢出。

//函数原型
fn overflowing_div(self, rhs: Self) -> (Self, bool) {
    if self == Self::min_value() && rhs == -1 {
        (self, true)
    } else {
        (self / rhs, false)
    }
}

fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) 欧几里得除法,同样在被除数是最小值且除数为-1时有溢出。

fn overflowing_rem(self, rhs: Self) -> (Self, bool) 取余,溢出情况与除法相同。

fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) 欧几里得取余,溢出情况与除法相同。

const fn overflowing_neg(self) -> (Self, bool) 变换正负号,当self是类型内最小值时会发生溢出。

println!("{:?}", (-128_i8).overflowing_neg());
-----
(-128, true)

const fn overflowing_shl(self, rhs: u32) -> (Self, bool) 带溢出的左移rhs位。当移位量大于类型字节数-1时发生溢出,溢出后则重新再次左移。所以移位rhs次与 rhs % 8 次结果是相同的。

(0x50_i8).overflowing_shl(7);
(0x50_i8).overflowing_shl(9);
-----
(0x0, false)
(0xA0, true)

const fn overflowing_shr(self, rhs: u32) -> (Self, bool) 带溢出的右移。

fn overflowing_abs(self) -> (Self, bool) 带溢出的绝对值,负数时,可参考overflowing_neg()方法。

fn overflowing_pow(self, mut exp: u32) -> (Self, bool) 带溢出的乘方。其溢出实现如下,在计算过程中发生溢出时,会使用溢出计算得到的值继续计算。

pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
    let mut base = self;
    let mut acc: Self = 1;
    let mut overflown = false;
    // Scratch space for storing results of overflowing_mul.
    let mut r;

    while exp > 1 {
        if (exp & 1) == 1 {
            r = acc.overflowing_mul(base);
            acc = r.0;
            overflown |= r.1;
        }
        exp /= 2;
        r = base.overflowing_mul(base);
        base = r.0;
        overflown |= r.1;
    }

    // Deal with the final bit of the exponent separately, since
    // squaring the base afterwards is not necessary and may cause a
    // needless overflow.
    if exp == 1 {
        r = acc.overflowing_mul(base);
        acc = r.0;
        overflown |= r.1;
    }

    (acc, overflown)
}

checked_* 系列:

checked_* 系列其后缀名称与overflowing_* 系列一致,但返回值是Option类型,溢出会返回None。

wrapping_* 系列:

wrapping_* 系列方法但后缀与overflowing_* 系列一致,返回值为同类型计算结果,与overflowing_* 计算结果相同,大部分溢出使用截断策略。

saturating_* 系列:

方法较少,溢出时会返回边界值。

const fn saturating_add(self, rhs: Self) -> Self 加法。

const fn saturating_sub(self, rhs: Self) -> Self 减法。

fn saturating_neg(self) -> Self 变换正负号。

fn saturating_abs(self) -> Self 绝对值。

fn saturating_mul(self, rhs: Self) -> Self 乘法。其内部使用checked_mul实现。

pub fn saturating_mul(self, rhs: Self) -> Self {
    self.checked_mul(rhs).unwrap_or_else(|| {
        if (self < 0 && rhs < 0) || (self > 0 && rhs > 0) {
            Self::max_value()
        } else {
            Self::min_value()
        }
    })
}

fn saturating_pow(self, exp: u32) -> Self 幂运算,内部使用checked_pow实现。

pub fn saturating_pow(self, exp: u32) -> Self {
    match self.checked_pow(exp) {
        Some(x) => x,
        None if self < 0 && exp % 2 == 1 => Self::min_value(),
        None => Self::max_value(),
    }
}

本文分享自微信公众号 - 可回收BUG(way-of-full-stack)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券