有效地实现地板/欧几里得整数除法
向下除法是指结果始终向下取整(朝向 −∞),而不是朝向 0:
是否可以在 C/C++ 中有效实现地板或欧几里得整数除法?
(显而易见的解决方案是检查股息的符号)
Floored division is when the result is always floored down (towards −∞), not towards 0:
Is it possible to efficiently implement floored or euclidean integer division in C/C++?
(the obvious solution is to check the dividend's sign)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我编写了一个测试程序来对此处提出的想法进行基准测试:
结果:
因此,根据我的结果,检查符号是最快的:
I've written a test program to benchmark the ideas presented here:
Results:
So, according to my results, checking the sign is the fastest:
五年后我重新审视这个问题,因为这也与我相关。我对 x86-64 的两个纯 C 版本和两个内联汇编版本进行了一些性能测量,结果可能很有趣。
地板划分的测试变体是:
CMOV
版本。以下是我的基准测试程序:
我使用 GCC 4.9.2 使用
gcc -march=native -Ofast
编译了该程序,在我的 Core i5-2400 上的结果如下。每次运行的结果都相当可重复——至少它们总是以相同的顺序着陆。因此,
CMOV
实现至少胜过其他实现。让我惊讶的是,变体 2 远远超过了它的纯 C 版本(变体 1)。我认为编译器应该能够发出至少与我的代码一样高效的代码。以下是一些其他平台,用于比较:
AMD Athlon 64 X2 4200+、GCC 4.7.2:
Xeon E3-1271 v3、GCC 4.9。 2:
最后一点,我也许应该警告不要过于认真地对待
CMOV
版本的明显性能优势,因为在现实世界中,其他版本中的分支可能不会像此基准测试中那样完全随机,并且如果分支预测器可以完成合理的工作,则分支版本可能会更好。然而,现实情况在很大程度上取决于实践中使用的数据,因此尝试进行任何通用基准测试可能毫无意义。I'm revisiting this question five years later, as this is relevant for me too. I did some performance measurements on two pure-C versions and two inline-assembly versions for x86-64, and the results may be interesting.
The tested variants of floored division are:
CMOV
version implemented in assembly.The following is my benchmark program:
I compiled this with
gcc -march=native -Ofast
using GCC 4.9.2, and the results, on my Core i5-2400, were as follows. The results are fairly reproducible from run to run -- they always land in the same order, at least.So the
CMOV
implementation blows the others out of the water, at least. What surprises me is that variant 2 out-does its pure-C version (variant 1) by a fairly wide margin. I'd have thought the compiler should be able to emit code at least as efficient as mine.Here are some other platforms, for comparison:
AMD Athlon 64 X2 4200+, GCC 4.7.2:
Xeon E3-1271 v3, GCC 4.9.2:
As a final note, I should perhaps warn against taking the apparent performance advantage of the
CMOV
version too seriously, because in the real world, the branch in the other versions will probably not be as completely random as in this benchmark, and if the branch predictor can do a reasonable job, the branching versions may turn out to be better. However, the realities of that will depend quite a bit on the data that are being used in practice, and so is probably pointless to try and do any generic benchmark of.提出一些无分支的东西来根据符号纠正结果可能会更有效,因为分支的成本很高。
请参阅 第 2 章 的第 20 页。 /" rel="nofollow">黑客之乐 了解如何访问该标志。
It could be more efficient to come up with something branch free to correct the result based on the sign, as branches are expensive.
See page 20ff of Chapter 2 in Hacker's Delight on how to access the sign.
请注意:x86 sar 指令在涉及 2 的幂时执行向下除法。
Just a note: the x86
sar
instruction performs floored division when it comes to powers of two.由于 IEEE-754 指定向 -inf 舍入作为所需舍入模式之一,我想您问题的答案是肯定的。但也许您可以解释一下您是否想知道如果编写编译器,将如何实现该过程,或者想知道如何使用特定编译器来执行该操作?
Since IEEE-754 specifies round towards -inf as one of the required rounding modes I imagine that the answer to your question is yes. But perhaps you can explain whether you want to know how one would implement the procedure if one were writing the compiler, or to know how to use a particular compiler to perform the operation ?
是的。
我完全同意,并且很难相信存在更快的替代方案。
Yes.
I agree completely, and would find it hard to believe there exists an alternative that is significantly faster.