如果你有一个浮点数double num_float = 5.0;
和以下两个条件。
if(num_float > 3)
{
//...
}
if(num_float > 3.0)
{
//...
}
Q:前一种比较会因为转换3
成浮点数比较慢,还是真的没有区别?
显然,我假设时间延迟充其量可以忽略不计,但在 while(1) 循环中,我认为从长远来看,可能会丢失相当多的时间(如果它真的更慢的话)。
如果你有一个浮点数double num_float = 5.0;
和以下两个条件。
if(num_float > 3)
{
//...
}
if(num_float > 3.0)
{
//...
}
Q:前一种比较会因为转换3
成浮点数比较慢,还是真的没有区别?
显然,我假设时间延迟充其量可以忽略不计,但在 while(1) 循环中,我认为从长远来看,可能会丢失相当多的时间(如果它真的更慢的话)。
由于“as-if”规则,允许编译器在编译时将文字转换为浮点值。如果这会产生更好的代码,那么好的编译器就会这样做。
为了针对您的编译器和目标平台明确回答您的问题,您需要检查编译器发出的内容以及它的执行方式。但是,如果任何主流编译器都没有将这两个 if 语句中的任何一个转换为最有效的代码,我会感到惊讶。
如果该值是一个常量,那么应该没有任何区别,因为编译器会将常量转换为浮点数作为编译的一部分[除非编译器决定使用“将浮点数与整数比较”指令]。
如果该值是一个整数 VARIABLE,那么将有一条额外的指令将整数值转换为浮点数 [再次强调,除非编译器可以使用“将浮点数与整数比较”指令]。
增加整个过程的时间(如果有的话)很大程度上取决于处理器、浮点指令的工作方式等。
与性能真正重要的任何事情一样,衡量替代方案。最好在不止一种类型的硬件上(例如,如果是 PC,AMD 和 Intel 处理器),然后决定哪个是更好的选择。否则,您可能会发现自己在调整代码以使其在您的硬件上运行良好,但在其他一些硬件上则更糟。这不是一个好的优化——除非你曾经运行的唯一机器是你自己的。
注意:这将需要对您的目标硬件重复。下面的代码只是很好地展示了所说的内容。
有常数:
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
铿锵 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
结论:如果与常数比较,没有区别。
带变量:
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
铿锵 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 的回答已经解释的那样。
Q:前一种比较是不是因为3转为浮点数比较慢,还是真的没有区别?
A)只需将其指定为整数。一些芯片有一个在运行时比较整数的特殊指令,但这并不重要,因为编译器会选择最好的。在某些情况下,它可能会在编译时根据目标体系结构将其转换为 3.0。在其他情况下,它将保留为 int。但是因为你特别想要 3 然后指定 '3'
显然,我假设时间延迟充其量可以忽略不计,但在 while(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;
}
这将大大提高比较速度。