很久以前,在有关古代FORTRAN的书中,我看到一种说法,即使用带有浮点变量的整数常量会比较慢,因为首先需要将常量转换为浮点形式:
double a = ..;
double b = a*2; // 2 -> 2.0 first
double c = a*2.0;
在现代C ++中编写2.0而不是2仍然有益吗?如果不是这样,可能应该首选“整数版本”,因为2.0更长,并且对人类读者没有任何影响。
我使用复杂的长表达式,其中这些“ .0”会影响性能或可读性(如果有的话)。
答案 0 :(得分:4)
首先要涵盖其他答案,2
和2.0
不会造成性能差异,这将在编译时进行检查以创建正确的值。但是要回答这个问题:
在现代C ++中编写2.0而不是2仍然有益吗?
绝对。
但这不是因为性能,而是因为可读性和错误。想象一下以下操作:
double a = (2 / someOtherNumber) * someFloat;
someOtherNumber
是什么类型?因为如果它是integer
类型,则由于整数除法会遇到麻烦。 2.0
或2.0f
具有明显的优势:
答案 1 :(得分:3)
让我们比较程序集的输出。
double foo(double a)
{
return a * 2;
}
double bar(double a)
{
return a * 2.0f;
}
double baz(double a)
{
return a * 2.0;
}
产生
0000000000000000 <foo>: //double x int
0: f2 0f 58 c0 addsd %xmm0,%xmm0 // add with itself
4: c3 retq // return (quad)
5: 90 nop // padding
6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) // padding
d: 00 00 00
0000000000000010 <bar>: //double x float
10: f2 0f 58 c0 addsd %xmm0,%xmm0 // add with itself
14: c3 retq // return (quad)
15: 90 nop // padding
16: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) // padding
1d: 00 00 00
0000000000000020 <baz>: //double x double
20: f2 0f 58 c0 addsd %xmm0,%xmm0 // add with itself
24: c3 retq // return (quad)
如您所见,它们都是相等的,根本不执行乘法。
即使在进行实数乘法(a*5
)时,它们都相等,并且性能低至
0: f2 0f 59 05 00 00 00 mulsd 0x0(%rip),%xmm0 # 8 <foo+0x8>
7: 00
8: c3 retq
@ Goswin-Von-Brederlow说,使用非常量表达式将导致不同的汇编。让我们像上面的例子一样测试它,但是要带有以下签名。
double foo(double a, int b); //int, float, double for foo/bar/baz
这将导致输出:
0000000000000000 <foo>: //double x int
0: 66 0f ef c9 pxor %xmm1,%xmm1 // clear xmm1
4: f2 0f 2a cf cvtsi2sd %edi,%xmm1 // convert edi (second argument) to double
8: f2 0f 59 c1 mulsd %xmm1,%xmm0 // mul xmm1 with xmm0
c: c3 retq // return
d: 0f 1f 00 nopl (%rax) // padding
0000000000000010 <bar>: //double x float
10: f3 0f 5a c9 cvtss2sd %xmm1,%xmm1 // convert float to double
14: f2 0f 59 c1 mulsd %xmm1,%xmm0 // mul
18: c3 retq // return
19: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) // padding
0000000000000020 <baz>: //double x double
20: f2 0f 59 c1 mulsd %xmm1,%xmm0 // mul directly
24: c3 retq // return
在这里您可以看到(运行时)从类型到双精度的转换,这当然会导致(运行时)开销。
答案 2 :(得分:2)
以下代码:
double f1(double a) {
double b = a*2;
return b;
}
double f2(double a) {
double c = a*2.0;
return c;
}
...使用Clang在gcc.godbolt.org上编译时,会产生以下程序集:
f1(double): # @f1(double)
addsd xmm0, xmm0
ret
f2(double): # @f2(double)
addsd xmm0, xmm0
ret
您可以看到两个函数完全相同,并且编译器甚至用加法代替了乘法。我希望这个千年以来的所有C ++编译器都可以做到这一点-相信他们,它们非常聪明。
答案 3 :(得分:0)
不,不是更快。如果编译器知道该数字是多少,为什么还要等到运行时才将其转换为浮点数呢?我想,如果您完全禁用了优化功能,那么您可能会说服某些极其笨拙的编译器来执行此操作,但是我所知道的所有编译器理所当然都会进行该优化。
现在,如果您使用a*b
的浮点类型和a
的整数类型来做b
,并且在某些可能导致会对性能产生重大影响(特别是如果您最近才计算b
的话)但是就文字而言,编译器已经为您服务。