C++ 除法中什么更快?双人/浮动/UInt32/UInt64?在C++/C

C++ 除法中什么更快?双人/浮动/UInt32/UInt64?在C++/C,c++,floating-point,performance,double,32bit-64bit,C++,Floating Point,Performance,Double,32bit 64bit,我做了一些速度测试,以找出什么是最快的,当做乘法或除法的数字。我必须努力工作才能打败乐观主义者。我得到了一些毫无意义的结果,比如一个巨大的循环在2微秒内运行,或者乘法和除法的速度相同(如果这是真的话) 在我最终努力克服了足够多的编译器优化之后,我仍然让它优化速度,我得到了这些速度结果。他们可能对其他人感兴趣 如果我的测试仍然有缺陷,请让我知道,但请注意,我只花了两个小时写了这篇废话:p 64 time: 3826718 us 32 time: 2476484 us D(mul) time: 93

我做了一些速度测试,以找出什么是最快的,当做乘法或除法的数字。我必须努力工作才能打败乐观主义者。我得到了一些毫无意义的结果,比如一个巨大的循环在2微秒内运行,或者乘法和除法的速度相同(如果这是真的话)

在我最终努力克服了足够多的编译器优化之后,我仍然让它优化速度,我得到了这些速度结果。他们可能对其他人感兴趣

如果我的测试仍然有缺陷,请让我知道,但请注意,我只花了两个小时写了这篇废话:p

64 time: 3826718 us
32 time: 2476484 us
D(mul) time: 936524 us
D(div) time: 3614857 us
S time: 1506020 us
使用双精度“乘除”似乎是除法的最快方法,其次是整数除法。我没有测试除法的准确性。“适当划分”是否更准确?在这些速度测试结果之后,我不想再去了解,因为我只想对一个基数为10的常量使用整数除法,并让我的编译器为我优化它;)(而且也不会破坏它的优化)

下面是我用来获得结果的代码:

#include <iostream>

int Run(int bla, int div, int add, int minus) {
    // these parameters are to force the compiler to not be able to optimise away the
    // multiplications and divides :)
    long LoopMax = 100000000;

    uint32_t Origbla32 = 1000000000;
    long i = 0;

    uint32_t bla32 = Origbla32;
    uint32_t div32 = div;
    clock_t Time32 = clock();
    for (i = 0; i < LoopMax; i++) {
        div32 += add;
        div32 -= minus;
        bla32 = bla32 / div32;
        bla32 += bla;
        bla32 = bla32 * div32;
    }
    Time32 = clock() - Time32;

    uint64_t bla64 = bla32;
    clock_t Time64 = clock();
    uint64_t div64 = div;
    for (long i = 0; i < LoopMax; i++) {
        div64 += add;
        div64 -= minus;
        bla64 = bla64 / div64;
        bla64 += bla;
        bla64 = bla64 * div64;
    }
    Time64 = clock() - Time64;

    double blaDMul = Origbla32;
    double multodiv = 1.0 / (double)div;
    double multomul = div;
    clock_t TimeDMul = clock();
    for (i = 0; i < LoopMax; i++) {
        multodiv += add;
        multomul -= minus;
        blaDMul = blaDMul * multodiv;
        blaDMul += bla;
        blaDMul = blaDMul * multomul;
    }
    TimeDMul = clock() - TimeDMul;

    double blaDDiv = Origbla32;
    clock_t TimeDDiv = clock();
    for (i = 0; i < LoopMax; i++) {
        multodiv += add;
        multomul -= minus;
        blaDDiv = blaDDiv / multomul;
        blaDDiv += bla;
        blaDDiv = blaDDiv / multodiv;
    }
    TimeDDiv = clock() - TimeDDiv;

    float blaS = Origbla32;
    float divS = div;
    clock_t TimeS = clock();
    for (i = 0; i < LoopMax; i++) {
        divS += add;
        divS -= minus;
        blaS = blaS / divS;
        blaS += bla;
        blaS = blaS * divS;
    }
    TimeS = clock() - TimeS;

    printf("64 time: %i us  (%i)\n", (int)Time64, (int)bla64);
    printf("32 time: %i us  (%i)\n", (int)Time32, bla32);

    printf("D(mul) time: %i us  (%f)\n", (int)TimeDMul, blaDMul);
    printf("D(div) time: %i us  (%f)\n", (int)TimeDDiv, blaDDiv);
    printf("S time: %i us  (%f)\n", (int)TimeS, blaS);

    return 0;
}

int main(int argc, char* const argv[]) {
    Run(0, 10, 0, 0); // adds and minuses 0 so it doesn't affect the math, only kills the opts
    return 0;
}
#包括
int运行(int bla、int div、int add、int减){
//这些参数将迫使编译器无法优化
//乘法和除法:)
长循环最大值=100000000;
uint32_t Origbla32=100000000;
长i=0;
uint32_t bla32=原始LA32;
uint32_t div32=div;
时钟时间32=时钟();
对于(i=0;i
执行某些算术的方法有很多种,因此可能没有一个单一的答案(移位、分数乘法、实际除法、对数单位的一些往返,等等;根据操作数和资源分配,这些可能都有不同的相对成本)

让编译器处理它拥有的程序和数据流信息


对于适用于x86上汇编的一些数据,您可以查看:

什么是最快的将完全取决于目标体系结构。在这里,您似乎只对您碰巧所在的平台感兴趣,从您的执行时间来看,这似乎是64位x86,Intel(Core2?)或AMD

也就是说,在许多平台上,浮点乘逆运算速度最快,但正如您所推测的,通常不如浮点除法精确(两次取整而不是一次取整——这对您的使用是否重要是另一个问题)。总的来说,你最好重新安排你的算法使用更少的除法,而不是为了尽可能地提高除法的效率(最快的除法就是你不做的除法),并且在你花时间进行优化之前确保基准测试,因为在除法上遇到瓶颈的算法很少

此外,如果您有整数源并且需要整数结果,请确保在基准测试中包含整数和浮点之间转换的成本

由于您对特定计算机上的计时感兴趣,您应该知道Intel现在在其计算机中发布此信息。具体而言,您将对附录C第3.1节“寄存器操作数的延迟和吞吐量”中的表格感兴趣


请注意,整数除法计时在很大程度上取决于所涉及的实际值。根据该指南中的信息,您的计时例程似乎仍然有相当大的开销,因为您测量的性能比与Intel发布的信息不匹配。

正如Stephen提到的,使用-但您还应该考虑使用SSE指令。它们可以在一条指令中进行4或8次除法/乘法运算

此外,对于一个部门来说,处理单个时钟周期是相当常见的。结果可能在几个时钟周期(称为延迟)内不可用,但下一个除法可以在此期间开始(与第一个除法重叠),只要它不需要第一个除法的结果。这是
double i32Time  = GetTime();
{
    volatile __int32 i = 4;
    __int32 count   = 0;
    __int32 max     = 1000000;
    while( count < max )
    {
        i /= 61;
        count++;
    }
}
i32Time = GetTime() - i32Time;

double i64Time  = GetTime();
{
    volatile __int64 i = 4;
    __int32 count   = 0;
    __int32 max     = 1000000;
    while( count < max )
    {
        i /= 61;
        count++;
    }
}
i64Time = GetTime() - i64Time;


double fTime    = GetTime();
{
    volatile float i = 4;
    __int32 count   = 0;
    __int32 max     = 1000000;
    while( count < max )
    {
        i /= 4.0f;
        count++;
    }
}
fTime   = GetTime() - fTime;

double fmTime   = GetTime();
{
    volatile float i = 4;
    const float div = 1.0f / 4.0f;
    __int32 count   = 0;
    __int32 max     = 1000000;
    while( count < max )
    {
        i *= div;
        count++;
    }
}
fmTime  = GetTime() - fmTime;

double dTime    = GetTime();
{
    volatile double i = 4;
    __int32 count   = 0;
    __int32 max     = 1000000;
    while( count < max )
    {
        i /= 4.0f;
        count++;
    }
}
dTime   = GetTime() - dTime;

double dmTime   = GetTime();
{
    volatile double i = 4;
    const double div = 1.0f / 4.0f;
    __int32 count   = 0;
    __int32 max     = 1000000;
    while( count < max )
    {
        i *= div;
        count++;
    }
}
dmTime  = GetTime() - dmTime;


DebugOutput( _T( "%f\n" ), i32Time );
DebugOutput( _T( "%f\n" ), i64Time );
DebugOutput( _T( "%f\n" ), fTime );
DebugOutput( _T( "%f\n" ), fmTime );
DebugOutput( _T( "%f\n" ), dTime );
DebugOutput( _T( "%f\n" ), dmTime );

DebugBreak();
0.006622
0.054654
0.006283
0.006353
0.006203
0.006161