如何比较 C++ 中 log() 和 fp 除法的性能?

Posted

技术标签:

【中文标题】如何比较 C++ 中 log() 和 fp 除法的性能?【英文标题】:How can I compare the performance of log() and fp division in C++? 【发布时间】:2011-02-20 22:57:51 【问题描述】:

我在 C++ 中使用基于日志的类来存储非常小的浮点值(否则这些值超出了double 的范围)。由于我正在执行大量的乘法运算,这具有将乘法转换为和的额外好处。

但是,在我的算法的某个时刻,我需要将标准 double 值除以 integer 值,而不是将 *= 值除以基于日志的值。我已经为我的基于日志的类重载了*= 运算符,并且首先通过运行log() 将右侧的值转换为基于日志的值,然后添加到左侧的值中。 因此实际执行的操作是浮点除法、log() 和浮点求和。

我的问题是首先将分母转换为基于对数的值是否会更快,这将用浮点减法代替浮点除法,产生以下操作链:两次log(),浮点-点减法,浮点求和。

最后,这归结为浮点除法是比log()快还是慢。我怀疑一个常见的答案是这取决于编译器和架构,所以我会说我在 darwin 10.3.0 上使用 Apple 的 gcc 4.2。不过,我希望得到一个关于这两个运营商的速度的一般评论和/或关于如何自己衡量差异的想法的答案,因为这里可能会有更多事情发生,例如执行进行类型转换等的构造函数。

干杯!

【问题讨论】:

呃……微优化?选择更准确的。 @KennyTM:是的,绝对是微优化,但在这种情况下听起来好像是有道理的。 在一个展开的循环中运行它十亿次并计时,看在上帝的份上。这些事情不是意见问题。 运算是double/integerinteger还是double/integerdouble? 嗯,是微优化。但是,我正在开发的软件是一个基于贪婪搜索的 NP 难题优化,并且不能真正在少于 O(n4) 的时间内完成,所以每一点都有帮助:) @MSN:操作是(基于对数的 double)*(double/integer) 【参考方案1】:

你是否多次除以同一个整数?如果是这样,您可以改为乘以1./yourInteger,并且只进行一次除法。如果可能的话,这会比任何一个都快。

至于您的实际问题,它不仅取决于编译器和架构,还取决于微架构和数据。

在您的特定平台 (darwin/x86) 上,对于当前硬件 i5/i7:除法 (1) 约为 24 个周期,log( )(2) 约为 35 个周期。然而,由于除法只使用一个指令调度槽,硬件的重排序引擎可以在除法运行时进行其他有用的计算;相比之下,log( ) 是在软件中实现的,因此处理器将其他计算提升到对数延迟的机会较少。这意味着在实践中,除法通常会快一些。

1) 来自英特尔优化手册

2) 通过在紧密循环中调用 log( ) 并使用 mach_absolute_time( ) 获取挂壁时间来测量。

【讨论】:

乘以1./myInteger 非常好。没想到,谢谢!我目前正在使用老化的 2006 Core 2 Duo,但您的计算是一个很好的洞察力,正是我想要的。 @Ventzi:我挖出了我的“老化核心 2 duo”来做一些计时:35 个周期用于除法,47 个周期用于对数。 @StephenCanon : 你是如何计时的?【参考方案2】:

在 x86 架构上,对数比除法花费的时间要长得多:FYL2X 需要 85 个周期(吞吐量),而 FDIV 需要 40 个周期。如果其他架构有很大不同,我会感到惊讶。使用浮点除法。

【讨论】:

gcc/darwin(他正在使用)使用 SSE2 进行双精度算术,而不是 x87 单元。 log用软件实现,除法使用divsd指令。 @Stephen:感谢您提供的额外信息——这将使天平进一步有利于 div。 @Martin B:实际上,它使比较更加平等; divsd 在 i7 上需要 24 个周期,而 darwin log 实现需要 35 个周期(两个时间都是吞吐量)。在较旧的硬件上,它们仍然更加平等,因为早期的微架构具有较慢的除法器,但其他 SSE 操作以大致相同的速度运行。不过,分歧仍然存在。 @Martin B:这并不是那么快得惊人;在现代处理器上,35 个周期是永恒的(考虑:i7 内核能够在 35 个周期内发出 165 条指令)。令人震惊的是仍然如此缓慢的划分=) darwin libm 是开源的,在 APSL 下分发。不幸的是,log 以相当难以阅读的方式实现(单个源文件支持 loglog2log10log1p,因此您需要展开一堆预处理器符号以理解它)。我想说最重要的速度“技巧”是(1)它检测特殊情况而不需要任何浮点比较,(2)它使用矢量算术来减少核心多项式评估的延迟。 opensource.apple.com/source/Libm/Libm-315/Source/Intel/…【参考方案3】:

除法的主要问题是,尽管在大多数现代 CPU 上它是一条指令,但它通常具有较高的latency(在 PowerPC 上为 31 个周期 - 不确定 x86 上是什么)。但是,如果您有其他可以与除法同时发出的非相关指令,则可以掩埋其中的一些延迟。所以答案在某种程度上取决于你在包含你的除法的循环中拥有什么样的指令组合和依赖关系(更不用说你正在使用哪个 CPU)。

话虽如此,但我的直觉是,在大多数架构上,divide 会比 log 函数更快。

【讨论】:

【参考方案4】:

我很确定通过任何算法进行对数计算都会比 FP 除法更昂贵。

当然,唯一确定的方法是编写代码并衡量代码的性能。从您的描述看来,实现两个版本并并排尝试应该不会太难。

【讨论】:

以上是关于如何比较 C++ 中 log() 和 fp 除法的性能?的主要内容,如果未能解决你的问题,请参考以下文章

C++的大数除法最快速度的算法

C++ 中的除法舍入

C++:模拟定点除法/乘法

javascript除法如何取整

求最大公因数(辗转相除,更相止损)C++描述

求最大公因数(辗转相除,更相止损)C++描述