exp2应该比exp更快吗?

时间:2015-05-13 18:40:46

标签: math floating-point

我最感兴趣的是C / C ++中的“exp”和“exp2”函数,但这个问题可能与IEEE 754标准有关,而不是特定的语言特性。

在10年前的一个作业问题中,我试图按所需的周期,C函数对不同的浮点运算进行排序

double exp2 (double)

似乎比

略快
double exp (double)

鉴于“double”使用尾数的二进制表示,我觉得这个结果是合理的。

然而,今天,在以几种不同的方式再次测试这两种方式之后,我看不出任何可衡量的差异。所以我的问题是

  • exp2(理论上)应该比exp快吗?和
  • 是否存在任何可衡量的差异?和
  • 近年来答案有所改变吗?

3 个答案:

答案 0 :(得分:5)

有很多平台对他们的数学库不太关心,exp2(x)简单地实现为exp(x * log(2)),反之亦然。这些实现不能提供良好的准确性(或特别好的性能),但它们相当普遍。在这样做的平台上,一个函数与另一个函数一样昂贵,但是额外乘法的成本,无论哪个得到额外的乘法将是两者中较慢的。

在积极调整数学库并尝试提供良好准确性的平台上,这两个函数的性能非常相似。使用exp2生成结果的指数更容易,但获得高精度有效数可能需要更多的工作;这两个因素大致均匀,即性能通常相当于10-15%。从广义上讲,exp2通常是两者中较快的。

答案 1 :(得分:1)

  • exp2应该(理论上)比exp快吗?

是。
x86 FPU对非整数幂执行取幂的唯一方法是使用指令F2XM1来计算 2 x -1
x86上不存在 e x 指令 x86的任何C库代码都被强制使用 2 x 来计算expexp2

  • 是否应该有任何可衡量的差异?

没有。
区别仅在于单个FPU乘法,这对于现代处理器来说非常快。

  • 近年来答案有所改变吗?

是。
15 - 20年前,乘法的价格远远高于其他业务的价格。如今,乘法几乎和加法一样便宜。

答案 2 :(得分:0)

我进行了一些测量,希望你们中的一些人会发现它有用。

条件:

  • Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz(服务器在测试期间具有较高的CPU负载)
  • 编译器版本:g ++(Ubuntu 5.4.0-6ubuntu1〜16.04.12)5.4.0 20160609
  • 编译器选项:-static -std=gnu++0x -ffast-math -Ofast -flto

代码:

#include <iostream>
#include <random>
#include <cmath>
#include <chrono>

using namespace std;

int main()
{
    double g = 1/log(2);
    mt19937 engine(1000);
    uniform_real_distribution<double> u(0, 1);
    double sum = 0;

    auto begin = std::chrono::high_resolution_clock::now();

    for (int i = 0; i < 1e7/4; ++i) // for non-parallel, `for (int i = 0; i < 1e7; ++i)`
    {
        sum += exp2(u(engine)*g);   // for exp versions, sum += exp(u(engine)); for empty version, sum += u(engine)
        sum += exp2(u(engine)*g);   // removed for non-parallel
        sum += exp2(u(engine)*g);   // removed for non-parallel
        sum += exp2(u(engine)*g);   // removed for non-parallel
    }

    auto end = std::chrono::high_resolution_clock::now();
    cout << chrono::duration_cast<chrono::nanoseconds>(end - begin).count()/1000./1000 << "ms" << "\t"
         << sum << "\t" << g << " exp2 p4" << endl;
}

执行: for i in {1..100}; do ./exp2_p4.bin && ./exp_p4.bin && ./exp.bin && ./exp2.bin; done

结果

下表显示了平均运行时间(时间),以毫秒为单位的标准偏差和最快的情况。

|   name  | time (ms) | std (ms) | smallest (ms) |
|:-------:|:---------:|:--------:|:-------------:|
|  empty  |   244.7   |   26.2   |     130.9     |
|   exp   |   591.7   |   95.8   |     422.5     |
|   exp2  |   536.5   |   85.4   |     393.7     |
|  exp p4 |   612.3   |   89.6   |     433.2     |
| exp2 p4 |   557.2   |   87.6   |     396.8     |

对于一项操作,需要将其除以1e7。我通过从指数版本中减去空版本的时间来估算指数成本。这些值如下所示: A figure showing the time costs of exp and exp2

结论

与已接受的答案一致,即使打开-ffast-math

exp2也可以比使用gcc的Intel Xeon上的exp快11%。