Naw*_*waz 64 c c++ performance built-in
这可能看起来有点愚蠢但是看到Alexandre C 在其他主题中的回复,我很想知道如果内置类型有任何性能差异:
charVSshortVSint主场迎战float主场迎战double.
通常我们在现实生活中没有考虑这种性能差异(如果有的话),但我想知道这是出于教育目的.可以问的一般问题是:
整数算术和浮点运算之间是否有任何性能差异?
哪个更快?更快的原因是什么?请解释一下.
Ste*_*non 112
浮点数与整数:
从历史上看,浮点可能比整数运算慢得多.在现代计算机上,情况已经不再如此(在某些平台上速度稍慢,但除非您编写完美的代码并针对每个周期进行优化,否则差异将被代码中的其他低效率所淹没).
在有限的处理器上,如高端手机中的处理器,浮点可能比整数慢一些,但只要有硬件浮点可用,它通常在一个数量级(或更好)的范围内.值得注意的是,随着手机被要求运行越来越多的通用计算工作负载,这种差距正在迅速缩小.
在非常有限的处理器(便宜的手机和烤面包机)上,通常没有浮点硬件,因此需要在软件中模拟浮点运算.这很慢 - 比整数算术慢几个数量级.
正如我所说,人们期望他们的手机和其他设备的行为越来越像"真正的计算机",硬件设计师正在迅速加强FPU以满足这种需求.除非您追逐每个循环,或者您正在为极少或没有浮点支持的非常有限的CPU编写代码,否则性能差异对您来说无关紧要.
不同大小的整数类型:
通常,CPU在其原始字大小的整数上运行速度最快(有一些关于64位系统的警告).在现代CPU上,32位操作通常比8位或16位操作更快,但这在架构之间会有很大差异.另外,请记住,您不能单独考虑CPU的速度; 它是复杂系统的一部分.即使在16位数上运行比在32位数上运行慢2倍,当您使用16位数而不是32位表示数据时,可以将两倍的数据放入缓存层次结构中.如果这使得所有数据都来自缓存而不是经常缓存未命中之间的区别,那么更快的内存访问将胜过CPU的较慢操作.
其他说明:
矢量化进一步提升了平衡,支持更窄的类型(float以及8位和16位整数) - 您可以在相同宽度的矢量中执行更多操作.但是,良好的矢量代码很难编写,因此,如果没有大量细致的工作,就不会获得这种好处.
为什么会出现性能差异?
实际上只有两个因素会影响CPU上的操作是否快速:操作的电路复杂性以及用户对操作的快速需求.
(在合理范围内)如果芯片设计者愿意在这个问题上投入足够的晶体管,那么任何操作都可以快速完成.但晶体管需要花钱(或者更确切地说,使用大量晶体管会使您的芯片变大,这意味着您每个晶圆的芯片数量减少,产量降低,这会花费金钱),因此芯片设计人员必须平衡使用多少操作的复杂性,以及他们根据(感知的)用户需求来做这件事.粗略地说,您可能会考虑将操作分为四类:
high demand low demand
high complexity FP add, multiply division
low complexity integer add popcount, hcf
boolean ops, shifts
Run Code Online (Sandbox Code Playgroud)
高需求,低复杂度的操作几乎可以在任何CPU上快速运行:它们是低成本的结果,并为每个晶体管带来最大的用户利益.
高需求,高复杂度的操作将在昂贵的CPU(如计算机中使用的CPU)上快速运行,因为用户愿意为它们付费.你可能不愿意为你的烤面包机额外支付3美元来快速增加FP,但是,如此便宜的CPU会吝啬这些指令.
几乎所有处理器的低需求,高复杂度操作通常都会很慢; 没有足够的好处来证明成本合理.
如果有人不愿意考虑它们,那么低需求,低复杂度的操作会很快,否则就不存在.
进一步阅读:
jal*_*alf 11
绝对.
首先,当然,它完全取决于所讨论的CPU架构.
但是,积分和浮点类型的处理方式非常不同,因此以下情况几乎总是如此:
在某些CPU上,双精度可能比浮点数慢得多.在某些体系结构中,没有用于双精度的专用硬件,因此它们通过传递两个浮点大小的块来处理,从而使您的吞吐量更低,延迟增加一倍.在其他(例如x86 FPU)上,两种类型都转换为相同的内部格式80位浮点(在x86的情况下),因此性能相同.在其他情况下,float和double都有适当的硬件支持,但由于float具有较少的位,因此可以更快地完成,通常相对于双操作减少一点延迟.
免责声明:所有提及的时间和特征都是从内存中提取的.我看起来没什么,所以可能是错的.;)
对于不同的整数类型,答案根据CPU架构而有很大差异.x86架构由于其悠久的历史,必须本身支持8,16,32(以及今天的64)位操作,并且通常它们都同样快速(它们使用基本相同的硬件,并且只有零根据需要输出高位.
但是,在其他CPU上,小于a的数据类型int加载/存储的成本可能更高(向内存写入一个字节可能必须通过加载它所在的整个32位字来完成,然后进行位屏蔽以更新寄存器中的单个字节,然后将整个字写回).同样,对于大于的数据类型int,某些CPU可能必须将操作拆分为两个,分别加载/存储/计算下半部分和上半部分.
但是在x86上,答案是它并不重要.由于历史原因,CPU需要对每种数据类型都提供非常强大的支持.因此,您可能注意到的唯一区别是浮点运算具有更多延迟(但吞吐量相似,因此它们本身并不慢,至少如果您正确编写代码)
上面的第一个答案很棒,我将它的一小块复制到以下副本中(因为这是我首先结束的地方)。
我想提供以下代码,它分析了对各种整数大小的分配、初始化和一些算术:
#include <iostream>
#include <windows.h>
using std::cout; using std::cin; using std::endl;
LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;
void inline showElapsed(const char activity [])
{
QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
cout << activity << " took: " << ElapsedMicroseconds.QuadPart << "us" << endl;
}
int main()
{
cout << "Hallo!" << endl << endl;
QueryPerformanceFrequency(&Frequency);
const int32_t count = 1100100;
char activity[200];
//-----------------------------------------------------------------------------------------//
sprintf_s(activity, "Initialise & Set %d 8 bit integers", count);
QueryPerformanceCounter(&StartingTime);
int8_t *data8 = new int8_t[count];
for (int i = 0; i < count; i++)
{
data8[i] = i;
}
showElapsed(activity);
sprintf_s(activity, "Add 5 to %d 8 bit integers", count);
QueryPerformanceCounter(&StartingTime);
for (int i = 0; i < count; i++)
{
data8[i] = i + 5;
}
showElapsed(activity);
cout << endl;
//-----------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------//
sprintf_s(activity, "Initialise & Set %d 16 bit integers", count);
QueryPerformanceCounter(&StartingTime);
int16_t *data16 = new int16_t[count];
for (int i = 0; i < count; i++)
{
data16[i] = i;
}
showElapsed(activity);
sprintf_s(activity, "Add 5 to %d 16 bit integers", count);
QueryPerformanceCounter(&StartingTime);
for (int i = 0; i < count; i++)
{
data16[i] = i + 5;
}
showElapsed(activity);
cout << endl;
//-----------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------//
sprintf_s(activity, "Initialise & Set %d 32 bit integers", count);
QueryPerformanceCounter(&StartingTime);
int32_t *data32 = new int32_t[count];
for (int i = 0; i < count; i++)
{
data32[i] = i;
}
showElapsed(activity);
sprintf_s(activity, "Add 5 to %d 32 bit integers", count);
QueryPerformanceCounter(&StartingTime);
for (int i = 0; i < count; i++)
{
data32[i] = i + 5;
}
showElapsed(activity);
cout << endl;
//-----------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------//
sprintf_s(activity, "Initialise & Set %d 64 bit integers", count);
QueryPerformanceCounter(&StartingTime);
int64_t *data64 = new int64_t[count];
for (int i = 0; i < count; i++)
{
data64[i] = i;
}
showElapsed(activity);
sprintf_s(activity, "Add 5 to %d 64 bit integers", count);
QueryPerformanceCounter(&StartingTime);
for (int i = 0; i < count; i++)
{
data64[i] = i + 5;
}
showElapsed(activity);
cout << endl;
//-----------------------------------------------------------------------------------------//
getchar();
}
/*
My results on i7 4790k:
Initialise & Set 1100100 8 bit integers took: 444us
Add 5 to 1100100 8 bit integers took: 358us
Initialise & Set 1100100 16 bit integers took: 666us
Add 5 to 1100100 16 bit integers took: 359us
Initialise & Set 1100100 32 bit integers took: 870us
Add 5 to 1100100 32 bit integers took: 276us
Initialise & Set 1100100 64 bit integers took: 2201us
Add 5 to 1100100 64 bit integers took: 659us
*/
Run Code Online (Sandbox Code Playgroud)
我在 i7 4790k 上的 MSVC 结果:
初始化和设置 1100100 8 位整数花费:444us
将 5 添加到 1100100 8 位整数花费:358us
初始化和设置 1100100 16 位整数占用:666us
将 5 添加到 1100100 16 位整数占用:359us
初始化和设置 1100100 32 位整数花费:870us
将 5 添加到 1100100 32 位整数花费:276us
初始化和设置 1100100 64 位整数花费:2201us
将 5 添加到 1100100 64 位整数花费:659us
我认为没有人提到整数推广规则.在标准C/C++中,不能对小于的类型执行任何操作int.如果char或short恰好小于当前平台上的int,则它们被隐式提升为int(这是bug的主要来源).编译器需要进行隐式升级,没有违反标准就无法绕过它.
整数提升意味着语言中的操作(加法,按位,逻辑等)不会出现在比int更小的整数类型上.因此,对char/short/int的操作通常同样快,因为前者被提升为后者.
除了整数提升之外,还有"通常的算术转换",这意味着C努力使两个操作数相同,如果它们不同,则将其中一个转换为两者中较大的一个.
但是,CPU可以在8,16,32等级执行各种加载/存储操作.在8位和16位架构上,这通常意味着尽管有整数提升,但8位和16位类型更快.在32位CPU上,它实际上可能意味着较小的类型较慢,因为它希望将所有内容整齐地排列在32位块中.32位编译器通常优化速度,并在比指定空间更大的空间中分配更小的整数类型.
虽然通常较小的整数类型当然比较大的整数类型占用更少的空间,所以如果你打算优化RAM大小,他们更喜欢.