我可以在每次除法时禁用检查零除法吗?
Can I disable checking for zero division every time the division happens?
为了更好的理解Rustspanic/exception机制,我写了如下一段代码:
#![feature(libc)]
extern crate libc;
fn main() {
let mut x: i32;
unsafe {
x = libc::getchar();
}
let y = x - 65;
println!("{}", x);
let z = 1 / y;
println!("{}", z);
}
我想看看 Rust 如何处理被零除的情况。最初我假设它要么将未处理的 SIGFPE 带到脸上然后死去,要么它实现了一个处理程序并将其重新路由到恐慌(现在可以处理了吗?)。
代码很冗长,因为我想确保 Rust 在编译时知道某些东西为零时不会做任何事情 "smart",因此用户输入。只需给它一个 'A' 就可以了。
我发现 Rust 实际上生成的代码每次在除法发生之前都会检查零除法。我什至看了一次大会。 :-)
长话短说:我可以禁用此行为吗?我想对于更大的数据集,这会对性能产生相当大的影响。为什么不使用我们的 CPU 能力来为我们检测这些东西呢?我可以设置自己的信号处理程序并改为处理 SIGFPE 吗?
据an issue on Github来看,前段时间情况肯定有所不同。
我认为事先检查每个分区与 "zero-cost" 相去甚远。你怎么看?我是否漏掉了一些明显的东西?
I think checking every division beforehand is far away from "zero-cost". What do you think?
你测量了什么?
执行的指令数是性能非常差的代表;矢量化代码通常更冗长,但速度更快。
所以真正的问题是:这个分支的成本是多少?
由于故意除以 0 的可能性很小,而无意中除以 0 的可能性稍大一些,因此分支总是会被正确预测 除以 0 时除外。但是,考虑到恐慌的代价,错误预测的分支是你最不担心的。
因此,成本是:
- 稍微胖一点的组合,
- 分支预测器中的一个占用槽。
确切的影响很难确定,对于数学密集型代码,它可能会产生影响。虽然我会提醒你整数除法是 ~100 周期 1 开始,所以数学重的代码会尽可能地避开它(它可能是最耗时的一个) CPU).
中的说明
1 参见 Agner Fog's Instruction Table:例如关于 Intel Nehalem DIV 和 IDIV 关于 64 位积分分别有 28 到 90 个周期和 37 到 100 个周期的延迟。
除此之外,rustc 是在 LLVM 之上实现的,它委托实际代码生成。因此,rustc 在很多情况下都受 LLVM 的支配,这就是其中之一。
LLVM有两条整数除法指令:udiv and sdiv.
两者都有除数为 0 的未定义行为。
Rust 旨在消除未定义行为,因此 有 防止除以 0 的发生,以免优化器破坏发出的代码而无法修复。
它按照 LLVM 手册中的建议使用检查。
Long story short: Can I disable this behaviour?
是的,你可以:std::intrinsics::unchecked_div(a, b)
。
您的问题也适用于余数(这就是 Rust 调用 modulo): std::intrinsics::unchecked_rem(a, b)
的方式。
我检查了程序集输出 here 以将其与 C++ 进行比较。
在文档中指出:
This is a nightly-only experimental API. (core_intrinsics)
intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library
因此您必须使用每晚构建,并且由于 已经指出的原因,它不太可能以稳定的形式出现在标准库中。
为了更好的理解Rustspanic/exception机制,我写了如下一段代码:
#![feature(libc)]
extern crate libc;
fn main() {
let mut x: i32;
unsafe {
x = libc::getchar();
}
let y = x - 65;
println!("{}", x);
let z = 1 / y;
println!("{}", z);
}
我想看看 Rust 如何处理被零除的情况。最初我假设它要么将未处理的 SIGFPE 带到脸上然后死去,要么它实现了一个处理程序并将其重新路由到恐慌(现在可以处理了吗?)。
代码很冗长,因为我想确保 Rust 在编译时知道某些东西为零时不会做任何事情 "smart",因此用户输入。只需给它一个 'A' 就可以了。
我发现 Rust 实际上生成的代码每次在除法发生之前都会检查零除法。我什至看了一次大会。 :-)
长话短说:我可以禁用此行为吗?我想对于更大的数据集,这会对性能产生相当大的影响。为什么不使用我们的 CPU 能力来为我们检测这些东西呢?我可以设置自己的信号处理程序并改为处理 SIGFPE 吗?
据an issue on Github来看,前段时间情况肯定有所不同。
我认为事先检查每个分区与 "zero-cost" 相去甚远。你怎么看?我是否漏掉了一些明显的东西?
I think checking every division beforehand is far away from "zero-cost". What do you think?
你测量了什么?
执行的指令数是性能非常差的代表;矢量化代码通常更冗长,但速度更快。
所以真正的问题是:这个分支的成本是多少?
由于故意除以 0 的可能性很小,而无意中除以 0 的可能性稍大一些,因此分支总是会被正确预测 除以 0 时除外。但是,考虑到恐慌的代价,错误预测的分支是你最不担心的。
因此,成本是:
- 稍微胖一点的组合,
- 分支预测器中的一个占用槽。
确切的影响很难确定,对于数学密集型代码,它可能会产生影响。虽然我会提醒你整数除法是 ~100 周期 1 开始,所以数学重的代码会尽可能地避开它(它可能是最耗时的一个) CPU).
中的说明1 参见 Agner Fog's Instruction Table:例如关于 Intel Nehalem DIV 和 IDIV 关于 64 位积分分别有 28 到 90 个周期和 37 到 100 个周期的延迟。
除此之外,rustc 是在 LLVM 之上实现的,它委托实际代码生成。因此,rustc 在很多情况下都受 LLVM 的支配,这就是其中之一。
LLVM有两条整数除法指令:udiv and sdiv.
两者都有除数为 0 的未定义行为。
Rust 旨在消除未定义行为,因此 有 防止除以 0 的发生,以免优化器破坏发出的代码而无法修复。
它按照 LLVM 手册中的建议使用检查。
Long story short: Can I disable this behaviour?
是的,你可以:std::intrinsics::unchecked_div(a, b)
。
您的问题也适用于余数(这就是 Rust 调用 modulo): std::intrinsics::unchecked_rem(a, b)
的方式。
我检查了程序集输出 here 以将其与 C++ 进行比较。
在文档中指出:
This is a nightly-only experimental API. (core_intrinsics)
intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library
因此您必须使用每晚构建,并且由于