我仍在改进overflower以处理整数溢出。一个目标是能够使用#[overflow(wrap)]
来避免溢出时的恐慌。但是,我发现标准整数类型的.wrapping_div(_)
和.wrapping_rem(_)
函数在除以零时实际上是恐慌。编辑:更好地激发这个用例:在中断处理程序中,我们绝对想避免恐慌。我假设div-by-zero条件极不可能,但我们仍然需要为某些有效定义返回“有效”值。
一种可能的解决方案是使值饱和(我在使用#[overflow(saturate)]
注释代码时执行此操作),但这可能相对较慢(特别是因为其他更多操作也已饱和)。所以我想添加一个#[overflow(no_panic)]
模式,完全避免恐慌,在所有情况下几乎和#[overflow(wrap)]
一样快。
我的问题是:什么是返回某事(不关心什么)的最快方法,而不会因为将(除了余数)除以零而感到恐慌?
答案 0 :(得分:2)
免责声明:这不是一个非常严肃的答案。它几乎肯定比使用if语句检查除数是否为零的天真解决方案要慢。
#![feature(asm)]
fn main() {
println!("18 / 3 = {}", f(18, 3));
println!("2555 / 10 = {}", f(2555, 10));
println!("-16 / 3 = {}", f(-16, 3));
println!("7784388 / 0 = {}", f(7784388, 0));
}
fn f(x: i32, y: i32) -> i32 {
let z: i32;
unsafe {
asm!(
"
test %ecx, %ecx
lahf
and $$0x4000, %eax
or %eax, %ecx
mov %ebx, %eax
cdq
idiv %ecx
"
: "={eax}"(z)
: "{ebx}"(x), "{ecx}"(y)
: "{edx}"
);
}
z
}
答案 1 :(得分:1)
pub fn nopanic_signed_div(x: i32, y: i32) -> i32 {
if y == 0 || y == -1 {
// Divide by -1 is equivalent to neg; we don't care what
// divide by zero returns.
x.wrapping_neg()
} else {
// (You can replace this with unchecked_div to make it more
// obvious this will never panic.)
x / y
}
}
这在x86-64上生成以下内容,其中“rustc 1.11.0-nightly(6e00b5556 2016-05-29)”:
movl %edi, %eax
leal 1(%rsi), %ecx
cmpl $1, %ecx
ja .LBB0_2
negl %eax
retq
.LBB0_2:
cltd
idivl %esi
retq
它应该在其他平台上产生类似的东西。
至少需要一个分支,因为LLVM IR认为除以零是未定义的行为。分别检查0和-1将涉及额外的分支。有了这些限制,实际上没有其他选择。
(使用内联汇编可能会稍微提高一些东西,但这会是一个糟糕的主意,因为在除以常量的情况下,最终会生成更糟糕的代码。)
这个解决方案是否真的合适可能取决于你的目标是什么;除以零可能是一个逻辑错误,因此默默地接受它似乎是一个坏主意。