现代硬件上的浮点数与整数计算


100

我正在用C ++进行一些性能至关重要的工作,并且我们目前正在使用整数计算来解决那些固有的浮点问题,因为它“更快”。这会引起很多烦人的问题,并增加了很多烦人的代码。

现在,我记得读过有关浮点计算如何如此缓慢的信息,大约在386天左右,我相信(IIRC)有一个可选的协同处理器。但是,如今在使用指数级更复杂,功能更强大的CPU时,如果进行浮点或整数计算,那么“速度”没有区别吗?特别是由于与导致流水线停滞或从主内存中获取某些内容相比,实际的计算时间很小?

我知道正确的答案是在目标硬件上进行基准测试,什么是测试此硬件的好方法?我编写了两个微型C ++程序,并将它们的运行时间与Linux上的“时间”进行了比较,但是实际的运行时间变化太大(对我在虚拟服务器上运行没有帮助)。我一整天都没有运行数百个基准测试,制作图表等,我是否可以做一些事情来对相对速度进行合理测试?有什么想法或想法吗?我完全错了吗?

我使用的程序如下,它们在任何方面都不相同:

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>

int main( int argc, char** argv )
{
    int accum = 0;

    srand( time( NULL ) );

    for( unsigned int i = 0; i < 100000000; ++i )
    {
        accum += rand( ) % 365;
    }
    std::cout << accum << std::endl;

    return 0;
}

程式2:

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>

int main( int argc, char** argv )
{

    float accum = 0;
    srand( time( NULL ) );

    for( unsigned int i = 0; i < 100000000; ++i )
    {
        accum += (float)( rand( ) % 365 );
    }
    std::cout << accum << std::endl;

    return 0;
}

提前致谢!

编辑:我关心的平台是在台式机Linux和Windows计算机上运行的常规x86或x86-64。

编辑2(从下面的评论粘贴):我们目前有一个广泛的代码库。确实,我遇到了这样的概括,即“由于整数计算速度更快,因此请勿使用浮点数”-我正在寻找一种方法(如果甚至是正确的话)来反驳这种广义的假设。我意识到,如果不做所有工作并随后进行概要分析,就不可能为我们预测确切的结果。

无论如何,感谢您的出色回答和帮助。随时添加其他任何内容:)。


8
您现在所拥有的测试是微不足道的。程序集之间的差异可能也很小(例如,addl用代替fadd)。真正获得良好衡量的唯一方法是获取真实程序的核心部分,并分析其不同版本。不幸的是,如果不付出大量努力,这将非常困难。也许告诉我们目标硬件和编译器将帮助人们至少为您提供已有的经验,等等。关于整数的使用,我怀疑您可以创建一种fixed_point可以大大简化此类工作的模板类。
GManNickG 2010年

1
仍然有许多架构没有专用的浮点硬件-一些解释您所关注的系统的标签将帮助您获得更好的答案。
卡尔·诺鲁姆

3
我相信HTC Hero(android)中的硬件没有FPU,但Google NexusOne(android)中的硬件却没有。你的目标是什么?台式机/服务器电脑?上网本(可能是arm + linux)?手机?
SteelBytes 2010年

5
如果要在x86上使用快速FP,请尝试使用优化和SSE代码生成进行编译。SSE(任何版本)至少可以在单个周期中进行浮点加,减和乘。除法,修改和更高的功能将总是很慢。另请注意,它float可以提高速度,但通常double不会。
Mike D.

1
定点整数通过使用多个整数运算来防止结果溢出来逼近FP。这几乎总是比仅使用现代台式机CPU中功能强大的FPU慢。例如MAD(定点mp3解码器)比libmpg123慢,即使定点解码器的质量很好,libmpg123的舍入误差也较小。 wezm.net/technical/2008/04/mp3-decoder-libraries-在PPC G5上进行了基准测试。
彼得·科德斯

Answers:


35

las,我只能给您一个“取决于”答案...

根据我的经验,性能有很多很多变量,尤其是在整数和浮点数学之间。由于不同的处理器具有不同的“流水线”长度,因此每个处理器(甚至在x86之类的同一系列中)的处理器之间差异很大。同样,某些操作通常非常简单(例如加法),并且具有通过处理器的加速路径,而其他操作(例如除法)则需要更长,更长的时间。

另一个大变量是数据所在的位置。如果您只需要添加几个值,那么所有数据都可以驻留在缓存中,在缓存中可以将它们快速发送到CPU。缓存中已经有数据的非常非常慢的浮点运算比需要从系统内存中复制整数的整数运算快许多倍。

我假设您是在问这个问题,因为您正在开发性能至关重要的应用程序。如果您正在开发x86体系结构,并且需要更高的性能,则可能需要研究使用SSE扩展。这可以极大地加快单精度浮点运算的速度,因为可以一次对多个数据执行相同的操作,另外还有用于SSE操作的单独的寄存器组。(在第二个示例中,我注意到您使用“浮点数”而不是“双精度”,这让我认为您使用的是单精度数学)。

*注意:使用旧的MMX指令实际上会减慢程序运行速度,因为这些旧的指令实际上使用的寄存器与FPU相同,从而无法同时使用FPU和MMX。


8
在某些处理器上,FP数学运算可能比整数数学运算更快。Alpha处理器具有FP除法指令,但没有整数除法指令,因此整数除法必须在软件中完成。
加布

SSEx还会加快双精度运算的速度吗?对不起,我不是太熟悉,SSE
约翰内斯·绍布- litb

1
@ JohannesSchaub-litb:SSE2(x86-64的基线)打包了double-precision FP。double每个寄存器只有两个64位s,潜在的加速比float矢量化好的代码要小。在x86-64上标量floatdouble使用XMM寄存器,而旧版x87仅用于long double。(所以@ Dan:否,MMX寄存器与普通FPU寄存器不冲突,因为x86-64上的普通FPU是SSE单元。MMX毫无意义,因为如果您可以执行整数SIMD,则需要16字节xmm0..15而不是8 字节字节mm0..7,现代CPU的MMX比SSE吞吐量差。)
Peter Cordes

1
但是MMX和SSE * / AVX2整数指令确实会争夺相同的执行单元,因此一次使用这两种指令几乎没有用。只需使用更广泛的XMM / YMM版本即可完成更多工作。同时使用SIMD整数和FP竞争相同的寄存器,但是x86-64有16个。但是总吞吐量限制意味着并行使用整数和FP执行单元无法完成两倍的工作。
彼得·科德斯

49

例如(数字越少越快),

64位Intel Xeon X5550 @ 2.67GHz,gcc 4.1.2 -O3

short add/sub: 1.005460 [0]
short mul/div: 3.926543 [0]
long add/sub: 0.000000 [0]
long mul/div: 7.378581 [0]
long long add/sub: 0.000000 [0]
long long mul/div: 7.378593 [0]
float add/sub: 0.993583 [0]
float mul/div: 1.821565 [0]
double add/sub: 0.993884 [0]
double mul/div: 1.988664 [0]

32位双核AMD Opteron(tm)处理器265 @ 1.81GHz,gcc 3.4.6 -O3

short add/sub: 0.553863 [0]
short mul/div: 12.509163 [0]
long add/sub: 0.556912 [0]
long mul/div: 12.748019 [0]
long long add/sub: 5.298999 [0]
long long mul/div: 20.461186 [0]
float add/sub: 2.688253 [0]
float mul/div: 4.683886 [0]
double add/sub: 2.700834 [0]
double mul/div: 4.646755 [0]

正如丹指出,甚至当你规范化的时钟频率(可在本身会引起误解,流水线的设计),结果会大相径庭基于CPU架构(个别ALU / FPU性能以及实际的ALU /的FPU的数量可用每超标量设计中的内核会影响可以并行执行多少个独立操作 -由于下面的所有操作都是顺序依赖的,因此下面的代码未考虑后一个因素。)

穷人的FPU / ALU操作基准:

#include <stdio.h>
#ifdef _WIN32
#include <sys/timeb.h>
#else
#include <sys/time.h>
#endif
#include <time.h>
#include <cstdlib>

double
mygettime(void) {
# ifdef _WIN32
  struct _timeb tb;
  _ftime(&tb);
  return (double)tb.time + (0.001 * (double)tb.millitm);
# else
  struct timeval tv;
  if(gettimeofday(&tv, 0) < 0) {
    perror("oops");
  }
  return (double)tv.tv_sec + (0.000001 * (double)tv.tv_usec);
# endif
}

template< typename Type >
void my_test(const char* name) {
  Type v  = 0;
  // Do not use constants or repeating values
  //  to avoid loop unroll optimizations.
  // All values >0 to avoid division by 0
  // Perform ten ops/iteration to reduce
  //  impact of ++i below on measurements
  Type v0 = (Type)(rand() % 256)/16 + 1;
  Type v1 = (Type)(rand() % 256)/16 + 1;
  Type v2 = (Type)(rand() % 256)/16 + 1;
  Type v3 = (Type)(rand() % 256)/16 + 1;
  Type v4 = (Type)(rand() % 256)/16 + 1;
  Type v5 = (Type)(rand() % 256)/16 + 1;
  Type v6 = (Type)(rand() % 256)/16 + 1;
  Type v7 = (Type)(rand() % 256)/16 + 1;
  Type v8 = (Type)(rand() % 256)/16 + 1;
  Type v9 = (Type)(rand() % 256)/16 + 1;

  double t1 = mygettime();
  for (size_t i = 0; i < 100000000; ++i) {
    v += v0;
    v -= v1;
    v += v2;
    v -= v3;
    v += v4;
    v -= v5;
    v += v6;
    v -= v7;
    v += v8;
    v -= v9;
  }
  // Pretend we make use of v so compiler doesn't optimize out
  //  the loop completely
  printf("%s add/sub: %f [%d]\n", name, mygettime() - t1, (int)v&1);
  t1 = mygettime();
  for (size_t i = 0; i < 100000000; ++i) {
    v /= v0;
    v *= v1;
    v /= v2;
    v *= v3;
    v /= v4;
    v *= v5;
    v /= v6;
    v *= v7;
    v /= v8;
    v *= v9;
  }
  // Pretend we make use of v so compiler doesn't optimize out
  //  the loop completely
  printf("%s mul/div: %f [%d]\n", name, mygettime() - t1, (int)v&1);
}

int main() {
  my_test< short >("short");
  my_test< long >("long");
  my_test< long long >("long long");
  my_test< float >("float");
  my_test< double >("double");

  return 0;
}

8
你为什么要混合Mult和div?如果Mult比div快(或预期?),那不是很有趣吗?
Kyss Tao

13
在整数和浮点情况下,乘法都比除法快得多。除法性能还取决于数字的大小。我通常认为除法要慢15倍。
Sogartar 2012年

4
pastebin.com/Kx8WGUfg我接受了您的基准测试,并将每个操作分离到自己的循环中并添加volatile以确保。在Win64上,FPU未使用,MSVC不会为其生成代码,因此它在此处使用mulssdivssXMM指令进行编译,它们比Win32中的FPU快25倍。测试机为Core i5 M 520 @ 2.40GHz
James Dunne

4
@JamesDunne要小心,因为fp ops v很快就会非常快地达到0或+/- inf,(某些情况下)(某些情况下)某些fpu实现可能会(理论上)将其视作特例/快速反应。
vladr

3
该“基准”对于乱序执行没有数据并行性,因为每个操作都使用相同的累加器(v)完成。在最新的Intel设计中,根本没有流水线划分(divss/ divps具有10-14个周期的延迟,并且互惠吞吐量相同)。 mulss但是有5个周期的延迟,但每个周期可以发出一个。(或者在Haswell上每个周期两个,因为端口0和端口1都有FMA的乘数)。
彼得·科德斯

23

定点数学和浮点数学之间的实际速度可能存在显着差异,但是ALU和FPU的理论上最佳情况下的吞吐量完全无关。取而代之的是您的体系结构上未被计算(例如用于循环控制)使用的整数和浮点寄存器(实数寄存器,而不是寄存器名称)的数量,每种类型的元素数量都适合高速缓存行,可以考虑整数和浮点数学的不同语义进行优化-这些效果将占主导地位。算法的数据依存关系在这里起着重要作用,因此没有一般的比较可以预测问题的性能差距。

例如,整数加法是可交换的,因此,如果编译器看到像您用于基准测试的循环(假设随机数据是事先准备好的,这样就不会模糊结果),则它可以展开该循环并计算部分和没有依赖项,然后在循环终止时添加它们。但是对于浮点数,编译器必须按照您要求的顺序进行操作(您在其中具有序列点,因此编译器必须保证相同的结果,不允许重新排序),因此每个加法项都具有很强的依赖性前一个的结果。

您也可能一次将更多的整数操作数放入缓存中。因此,即使在FPU理论上吞吐量更高的机器上,定点版本也可能比浮动版本的性能高出一个数量级。


4
+1指出由于展开的常量整数运算,幼稚的基准测试如何产生0次循环。此外,如果未实际使用结果,则编译器可以完全放弃循环(整数或FP)。
vladr

结论是:必须调用一个以循环变量为参数的函数。因为我认为没有编译器能够看到该函数不执行任何操作,并且可以忽略该调用。由于存在通话开销,因此只有时间==(浮动时间-整数时间)的差异会很明显。
GameAlchemist 2013年

@GameAlchemist:作为内联的副作用,许多编译器确实消除了对空函数的调用。您必须努力防止这种情况。
Ben Voigt 2014年

OP听起来好像他在谈论将整数用于FP更自然适合的事情,因此要花费更多的整数代码来获得与FP代码相同的结果。在这种情况下,只需使用FP。例如,在具有FPU的硬件(例如台式机CPU)上,定点整数MP3解码器比浮点解码器慢(且舍入误差略大)。编解码器的定点实现主要存在于没有FP硬件,只有慢速仿真FP的精简ARM CPU上。
彼得·科德斯

第一点的一个示例:在带有AVX-512的x86-64上,只有16个GP寄存器,但有32个zmm寄存器,因此标量浮点数学运算可能会更快
phuclv

18

加法比快得多rand,因此您的程序(尤其是)毫无用处。

您需要确定性能热点并逐步修改程序。听起来您的开发环境有问题,需要首先解决。遇到小问题集,是否不可能在PC上运行程序?

通常,尝试使用整数算术进行FP作业会降低速度。


是的,以及在浮点版本中从rand整数到float的转换。有更好的方法来测试这一点的想法吗?
maxpenguin 2010年

1
如果您要分析速度,请查看POSIX timespec_t或类似的东西。记录循环开始和结束的时间,然后求出差值。然后将rand数据生成移出循环。确保算法从数组中获取所有数据并将其所有数据放入数组中。这本身就可以获取您的实际算法,并可以进行设置,malloc,结果打印,除了任务切换和中断之外的所有操作。
Mike D.

3
@maxpenguin:问题是您要测试什么。Artem假定您正在做图形,Carl考虑了您是否在没有FP的嵌入式平台上,我认为您正在为服务器编程。您不能概括或“编写”基准测试。基准是从程序的实际工作中抽取的。我可以告诉您的一件事是,如果您触摸程序中性能关键的元素,则无论如何,它都不会保持“基本上相同的速度”。
Potatoswatter

好点和好的答案。目前,我们拥有广泛的代码库。确实,我得出了这样的概括,即“由于整数计算速度更快,因此请勿使用浮点数”-我正在寻找一种方法(如果甚至是正确的话)来证明这种广义假设。我意识到,如果不做所有工作并事后进行分析,就不可能为我们预测确切的结果。无论如何,谢谢您的帮助。
maxpenguin 2010年

18

TIL(变化很大)。这是使用gnu编译器的一些结果(顺便说一句,我也通过在计算机上进行编译来检查,xenial的gnu g ++ 5.4比linaro的4.6.3快得多)

英特尔i7 4700MQ Xenial

short add: 0.822491
short sub: 0.832757
short mul: 1.007533
short div: 3.459642
long add: 0.824088
long sub: 0.867495
long mul: 1.017164
long div: 5.662498
long long add: 0.873705
long long sub: 0.873177
long long mul: 1.019648
long long div: 5.657374
float add: 1.137084
float sub: 1.140690
float mul: 1.410767
float div: 2.093982
double add: 1.139156
double sub: 1.146221
double mul: 1.405541
double div: 2.093173

英特尔i3 2370M具有相似的结果

short add: 1.369983
short sub: 1.235122
short mul: 1.345993
short div: 4.198790
long add: 1.224552
long sub: 1.223314
long mul: 1.346309
long div: 7.275912
long long add: 1.235526
long long sub: 1.223865
long long mul: 1.346409
long long div: 7.271491
float add: 1.507352
float sub: 1.506573
float mul: 2.006751
float div: 2.762262
double add: 1.507561
double sub: 1.506817
double mul: 1.843164
double div: 2.877484

英特尔(R)赛扬(R)2955U(运行xenial的Acer C720 Chromebook)

short add: 1.999639
short sub: 1.919501
short mul: 2.292759
short div: 7.801453
long add: 1.987842
long sub: 1.933746
long mul: 2.292715
long div: 12.797286
long long add: 1.920429
long long sub: 1.987339
long long mul: 2.292952
long long div: 12.795385
float add: 2.580141
float sub: 2.579344
float mul: 3.152459
float div: 4.716983
double add: 2.579279
double sub: 2.579290
double mul: 3.152649
double div: 4.691226

DigitalOcean 1GB Droplet Intel(R)Xeon(R)CPU E5-2630L v2(运行可靠)

short add: 1.094323
short sub: 1.095886
short mul: 1.356369
short div: 4.256722
long add: 1.111328
long sub: 1.079420
long mul: 1.356105
long div: 7.422517
long long add: 1.057854
long long sub: 1.099414
long long mul: 1.368913
long long div: 7.424180
float add: 1.516550
float sub: 1.544005
float mul: 1.879592
float div: 2.798318
double add: 1.534624
double sub: 1.533405
double mul: 1.866442
double div: 2.777649

AMD Opteron(tm)处理器4122(精确)

short add: 3.396932
short sub: 3.530665
short mul: 3.524118
short div: 15.226630
long add: 3.522978
long sub: 3.439746
long mul: 5.051004
long div: 15.125845
long long add: 4.008773
long long sub: 4.138124
long long mul: 5.090263
long long div: 14.769520
float add: 6.357209
float sub: 6.393084
float mul: 6.303037
float div: 17.541792
double add: 6.415921
double sub: 6.342832
double mul: 6.321899
double div: 15.362536

这使用http://pastebin.com/Kx8WGUfg中的代码作为benchmark-pc.c

g++ -fpermissive -O3 -o benchmark-pc benchmark-pc.c

我已经进行了多次通过,但是似乎通用数字是相同的。

一个值得注意的例外似乎是ALU mul和FPU mul。加减似乎微不足道。

这是上面的图表形式(单击以查看完整尺寸,降低速度更快,更可取):

以上数据图表

更新以适应@Peter Cordes

https://gist.github.com/Lewiscowles1986/90191c59c9aedf3d08bf0b129065cccc

i7 4700MQ Linux Ubuntu Xenial 64位(已应用至2018-03-13的所有补丁)
    short add: 0.773049
    short sub: 0.789793
    short mul: 0.960152
    short div: 3.273668
      int add: 0.837695
      int sub: 0.804066
      int mul: 0.960840
      int div: 3.281113
     long add: 0.829946
     long sub: 0.829168
     long mul: 0.960717
     long div: 5.363420
long long add: 0.828654
long long sub: 0.805897
long long mul: 0.964164
long long div: 5.359342
    float add: 1.081649
    float sub: 1.080351
    float mul: 1.323401
    float div: 1.984582
   double add: 1.081079
   double sub: 1.082572
   double mul: 1.323857
   double div: 1.968488
AMD Opteron(tm)处理器4122(精确的DreamHost共享主机)
    short add: 1.235603
    short sub: 1.235017
    short mul: 1.280661
    short div: 5.535520
      int add: 1.233110
      int sub: 1.232561
      int mul: 1.280593
      int div: 5.350998
     long add: 1.281022
     long sub: 1.251045
     long mul: 1.834241
     long div: 5.350325
long long add: 1.279738
long long sub: 1.249189
long long mul: 1.841852
long long div: 5.351960
    float add: 2.307852
    float sub: 2.305122
    float mul: 2.298346
    float div: 4.833562
   double add: 2.305454
   double sub: 2.307195
   double mul: 2.302797
   double div: 5.485736
Intel Xeon E5-2630L v2 @ 2.4GHz(Trusty 64-bit,DigitalOcean VPS)
    short add: 1.040745
    short sub: 0.998255
    short mul: 1.240751
    short div: 3.900671
      int add: 1.054430
      int sub: 1.000328
      int mul: 1.250496
      int div: 3.904415
     long add: 0.995786
     long sub: 1.021743
     long mul: 1.335557
     long div: 7.693886
long long add: 1.139643
long long sub: 1.103039
long long mul: 1.409939
long long div: 7.652080
    float add: 1.572640
    float sub: 1.532714
    float mul: 1.864489
    float div: 2.825330
   double add: 1.535827
   double sub: 1.535055
   double mul: 1.881584
   double div: 2.777245

gcc5可能会自动矢量化gcc4.6没有的内容?是否正在benchmark-pc衡量吞吐量和延迟的某种组合?在Haswell(i7 4700MQ)上,整数乘以每个时钟吞吐量为1,具有3个周期的延迟,但是整数加/减是每个时钟吞吐量为4,具有1个周期的延迟(agner.org/optimize)。因此,大概有很多循环开销会稀释这些数字,以使add和mul如此接近(长添加:0.824088与长mul:1.017164)。(gcc默认不展开循环,除非完全展开非常低的迭代次数)。
彼得·科德斯

顺便说一句,为什么它不测试intshort而又long?在Linux x86-64上short为16位(因此在某些情况下会导致部分寄存器变慢),而longlong long均为64位类型。(也许它是为x86-64仍使用32位的Windows设计的long?或者也许是为32位模式设计的。)在Linux上,x32 ABI long在64位模式下具有32 位,因此如果已安装库,gcc -mx32用于ILP32的编译器。或者只是使用-m32并查看long数字。
彼得·科德斯

而且,您应该真正检查编译器是否自动向量化了任何东西。例如,使用addpsxmm寄存器而不是x addss来做4 FP在一条与标量一样快的指令中并行添加addss。(-march=native用于允许使用您的CPU支持的任何指令集,而不仅限于x86-64的SSE2基准)。
彼得·科德斯

@cincodenada,请保留图表以显示完整的15条,以示其性能。
MrMesees'3

@PeterCordes我明天将尝试看,谢谢您的努力。
MrMesees '18

7

有两点要考虑-

现代硬件可以重叠指令,并行执行它们,并对它们重新排序以充分利用硬件。而且,即使仅在数组,循环计数器等中计算索引,任何有效的浮点程序也可能具有有效的整数工作,因此,即使您使用的是慢速浮点指令,它也可能在单独的硬件上运行与一些整数工作重叠。我的观点是,即使浮点指令比整数指令慢,您的整个程序也可能运行得更快,因为它可以利用更多的硬件。

与往常一样,唯一可以确保的方法是分析实际程序。

第二点是,当今大多数CPU都具有用于浮点的SIMD指令,这些指令可以同时对多个浮点值进行运算。例如,您可以将4个浮点数加载到单个SSE寄存器中,并对其并行执行4个乘法。如果您可以重写部分代码以使用SSE指令,则似乎它会比整数版本快。Visual c ++提供了用于执行此操作的编译器固有函数,有关某些信息,请参见http://msdn.microsoft.com/zh-cn/library/x5c07e2a(v=VS.80).aspx


应当注意,在Win64上,MSVC编译器不再生成FPU指令。浮点数总是在那里使用SIMD指令。这使得Win32和Win64之间在触发器方面存在很大的速度差异。
James Dunne 2013年

5

如果没有余数运算,则浮点版本会慢很多。由于所有加法都是顺序的,因此cpu将无法并行化求和。延迟至关重要。FPU添加延迟通常为3个周期,而整数添加为1个周期。但是,余数运算符的分频器可能是关键部分,因为它在现代CPU上尚未完全流水线化。因此,假设除法/余数指令将消耗大量时间,则由于添加延迟而导致的差异将很小。


4

除非您正在编写每秒被调用数百万次的代码(例如,在图形应用程序中在屏幕上绘制一条线),否则整数与浮点运算很少会成为瓶颈。

效率问题的通常第一步是分析代码,以查看运行时的实际使用位置。对此的linux命令是gprof

编辑:

尽管我想您总是可以使用整数和浮点数来实现线条绘制算法,但要多次调用它,看看它是否有所不同:

http://en.wikipedia.org/wiki/Bresenham's_algorithm


2
科学应用程序使用FP。FP的唯一优点是精度是尺度不变的。就像科学记数法。如果您已经知道数字的比例(例如,行长是像素数),则可以省去FP。但是在画线之前,这是不正确的。
Potatoswatter

4

如今,整数运算通常比浮点运算快一点。因此,如果您可以使用相同的整数和浮点运算来进行计算,请使用整数。但是,您在说“这会引起很多烦人的问题,并增加很多烦人的代码”。听起来您需要执行更多操作,因为您使用整数算术而不是浮点数。在这种情况下,浮点运算速度会更快,因为

  • 一旦您需要更多的整数运算,您可能就需要更多的运算,因此轻微的速度优势比其他运算所消耗的更多

  • 浮点代码更简单,这意味着编写代码的速度更快,这意味着如果速度至关重要,则可以花更多时间优化代码。


这里有很多疯狂的推测,没有考虑到硬件中存在的任何次要影响,这些次要影响通常会影响计算时间。这不是一个坏的起点,但是需要通过分析在每个特定的应用程序上进行检查,而不应将其视为福音书。
Ben Voigt 2014年

3

我运行了一个测试,仅将数字加1而不是rand()。结果(在x86-64上)为:

  • 短:4.260s
  • 整数:4.020s
  • 很长很长:3.350s
  • 浮动:7.330秒
  • 双:7.210秒

1
源代码,编译选项和计时方法?结果令我有些惊讶。
GManNickG 2010年

与OP相同的循环,用“ rand()%365”替换为“ 1”。没有优化。用户时间来自“时间”命令。
10年

13
“没有优化”是关键。您永远不会在关闭优化的情况下进行概要分析,而总是在“发布”模式下进行概要分析。
Dean Harding

2
不过,在这种情况下,优化关闭会强制执行操作,并且是故意进行的-循环可将时间扩展到合理的测量范围。使用常数1消除了rand()的成本。一个足够聪明的优化编译器将看到1增加了100,000,000次而没有出路,而在单个操作中仅增加了100000000。这样可以解决整个目标,不是吗?
斯坦·罗杰斯

7
@Stan,使变量可变。即使是聪明的优化编译器,也应该尊重多个操作。
vladr 2011年

0

根据过去那种非常可靠的“我所听到的东西”,整数计算的速度大约是浮点数的20到50倍,而如今却不到两倍。


1
请考虑再次考虑提供更多的意见(尤其是鉴于所收集到的事实意见似乎不成立)
MrMesees 2017年

1
@MrMesees虽然此答案并非十分有用,但我想说它与您所做的测试是一致的。历史上的琐事也可能很好。
JonatanÖström17年

作为一个曾经在286年代工作过的人,我可以确认;“是的,他们是!”
David H Parry19年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.