如何解决Rust溢出
我最近遇到的问题要求根据整数类型的位对边界进行整数运算。
例如,使用i32
整数执行add
操作,下面是一段伪代码来表达这个想法:
sum = a + b
max(min(sum,2147483647),-2147483648)
# if the sum is larger than 2147483647,then return 2147483647.
# if the sum is smaller than -2147483648,then return -2147483648.
为此,我天真地编写了以下丑陋的代码:
fn i32_add_handling_by_casting(a: i32,b: i32) -> i32 {
let sum: i32;
if (a as i64 + b as i64) > 2147483647 as i64 {
sum = 2147483647;
} else if (a as i64 + b as i64) < -2147483648 as i64 {
sum = -2147483648;
} else {
sum = a + b;
}
sum
}
fn main() {
println!("{:?}",i32_add_handling_by_casting(2147483647,1));
println!("{:?}",i32_add_handling_by_casting(-2147483648,-1));
}
代码运行良好;但是我的六种感觉告诉我,使用类型转换是有问题的。因此,我尝试使用传统的紧急(异常)处理来解决此问题……但我坚持使用以下代码(紧急结果无法检测到下溢或上溢):
use std::panic;
fn i32_add_handling_by_panic(a: i32,b: i32) -> i32 {
let sum: i32;
let result = panic::catch_unwind(|| {a + b}).ok();
match result {
Some(result) => { sum = result },None => { sum = ? }
}
sum
}
fn main() {
println!("{:?}",i32_add_handling_by_panic(2147483647,i32_add_handling_by_panic(-2147483648,-1));
}
总而言之,我有3个问题:
- 我的类型转换解决方案是否适用于强类型语言? (如果可能,我需要说明为什么有效或无效。)
- 还有其他更好的方法来解决此问题吗?
- 恐慌可以单独处理不同的异常吗?
解决方法
在这种情况下,Rust标准库有一个名为saturating_add
的方法,该方法支持您的用例:
assert_eq!(10_i32.saturating_add(20),30);
assert_eq!(i32::MIN.saturating_add(-1),i32::MIN);
assert_eq!(i32::MAX.saturating_add(1),i32::MAX);
在内部,它被实现为compiler intrinsic。
通常,此类问题并不能通过紧急解决来解决,而只能在特殊情况下进行清理。手写版本可能涉及类型转换,但只计算一次a as i64 + b as i64
。另外,这是一个使用checked_add
的版本,它会在发生溢出的情况下返回None
而不是出现紧急情况:
fn saturating_add(a: i32,b: i32) -> i32 {
if let Some(sum) = a.checked_add(b) {
sum
} else if a < 0 {
i32::MIN
} else {
i32::MAX
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。