上一次盘的是有符号整数的相关函数实现,包括一些位运算、几个科学计算方法等等,这回盘一下计算检测溢出的几个方法,以及其中的区别。
以下均处于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(),
}
}
完