浮点数与整数比较需要额外的时间吗?

时间:2013-02-14 22:07:46

标签: c++ performance floating-point type-conversion

如果您有一个浮点数double num_float = 5.0;和以下两个条件。

if(num_float > 3)
{
    //...
}

if(num_float > 3.0)
{
    //...
}

问:由于3转换为浮点数,执行前一次比较是否会更慢,或者根本没有差异?

显然我假设时间延迟最多可以忽略不计,但是在一段时间(1)循环中复杂化我认为从长远来看可能会丢失一大块时间(如果真的慢了)。

4 个答案:

答案 0 :(得分:4)

由于"as-if" rule,允许编译器在编译时将文字转换为浮点值。一个好的编译器会这样做,如果这会产生更好的代码。

为了明确地回答您的编译器和目标平台的问题,您需要检查编译器发出的内容及其执行方式。但是,如果任何主流编译器没有将两个if语句中的任何一个转换为最有效的代码,我会感到惊讶。

答案 1 :(得分:2)

如果值是常量,那么应该没有任何区别,因为编译器会将常量转换为float作为编译的一部分[除非编译器决定使用“compare float with integer”指令]。

如果值是整数VARIABLE,则会有一条额外的指令将整数值转换为浮点[再次,除非编译器可以使用“compare float with integer”指令]。

添加到整个过程的时间(如果有的话)多少取决于处理器,浮点指令的工作方式等等。

与性能真正重要的任何事情一样,衡量替代方案。最好是在多种类型的硬件上(例如AMD和Intel处理器,如果它是PC),然后决定哪个是更好的选择。否则,您可能会发现自己调整代码以在您的硬件上运行良好,但在某些其他硬件上更糟糕。这不是一个好的优化 - 除非您运行的唯一机器是您自己的。

答案 2 :(得分:1)

注意:您需要使用目标硬件重复此操作。下面的代码很好地说明了所说的内容。


with constants

bool with_int(const double num_float) {
  return num_float > 3;
}

bool with_float(const double num_float) {
  return num_float > 3.0;
}

g ++ 4.7.2(-O3 -march=native):

with_int(double):
  ucomisd       .LC0(%rip), %xmm0
  seta  %al
  ret
with_float(double):
  ucomisd       .LC0(%rip), %xmm0
  seta  %al
  ret
.LC0:
  .long 0
  .long 1074266112

clang 3.0(-O3 -march=native):

.LCPI0_0:
  .quad 4613937818241073152     # double 3.000000e+00
with_int(double):                           # @with_int(double)
  ucomisd       .LCPI0_0(%rip), %xmm0
  seta  %al
  ret

.LCPI1_0:
  .quad 4613937818241073152     # double 3.000000e+00
with_float(double):                        # @with_float(double)
  ucomisd       .LCPI1_0(%rip), %xmm0
  seta  %al
  ret

结论:与常数比较没有区别。


with variables

bool with_int(const double a, const int b) {
  return a > b;
}

bool with_float(const double a, const float b) {
  return a > b;
}

g ++ 4.7.2(-O3 -march=native):

with_int(double, int):
  cvtsi2sd      %edi, %xmm1
  ucomisd       %xmm1, %xmm0
  seta  %al
  ret
with_float(double, float):
  unpcklps      %xmm1, %xmm1
  cvtps2pd      %xmm1, %xmm1
  ucomisd       %xmm1, %xmm0
  seta  %al
  ret

clang 3.0(-O3 -march=native):

with_int(double, int):                          # @with_int(double, int)
  cvtsi2sd      %edi, %xmm1
  ucomisd       %xmm1, %xmm0
  seta  %al
  ret

with_float(double, float):                       # @with_float(double, float)
  cvtss2sd      %xmm1, %xmm1
  ucomisd       %xmm1, %xmm0
  seta  %al
  ret

结论:与变量进行比较时,发出的指令有所不同,正如Mats Peterson's answer已经解释过的那样。

答案 3 :(得分:0)

问:由于将3转换为浮点,执行前一次比较是否会更慢,或者根本没有差异?

A)只需将其指定为整数即可。有些芯片在运行时有一个特殊的指令用于比较整数,但这并不重要,因为编译器会选择最好的。在某些情况下,它可能会在编译时将其转换为3.0,具体取决于目标体系结构。在其他情况下,它会将其保留为int。但是因为你想要3具体,然后指定' 3'

显然我假设时间延迟最多可以忽略不计,但是在一段时间(1)循环中复杂化我认为从长远来看,可能会丢失一大块时间(如果真的慢了)。

A)编译器不会对这些代码做任何奇怪的事情。它会选择最好的东西,所以不应该有时间延迟。使用数字常量,编译器可以自由地执行最佳操作,无论它看起来是什么,只要它产生相同的结果。但是,你根本不想在while循环中复合这种类型的比较。而是使用整数循环计数器。浮点循环计数器会慢得多。如果你必须使用浮点作为循环计数器更喜欢单点32位数据类型并尽可能少地进行比较。

例如,您可以将问题分解为多个循环。

int x = 0;
float y = 0;
float finc = 0.1;
int total = 1000;
int num_times = total / finc;
num_times -= 2;// safety
// Run the loop in a safe zone using integer compares
while (x < num_times) {
  // Do stuff
  y += finc;
  x++;
}
// Now complete the loop using float compares
while (y < total) {
  y+= finc;
}

这将导致比较速度的严重改善。