#函数调用为什么那么慢?
我找到两种快速求绝对值的计算方法:
第一种为:
__forceinline int my_abs1(const int& value)
{
return (value ^ (value >> 31)) - (value >> 31);
}
第二种为:
__forceinline int my_abs2(const int& value)
{
return value * (1 - (value >> 31) << 1);
}
测试代码为:
int main()
{
int c = 1000000000;
clock_t start_time = clock();
for (int i = 0; i < c; i++)
{
abs(1);
abs(-1);
}
clock_t end_time = clock();
std::cout << static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << std::endl;
start_time = clock();
for (int i = 0; i < c; i++)
{
my_abs1(1);
my_abs1(-1);
}
end_time = clock();
std::cout << static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << std::endl;
start_time = clock();
for (int i = 0; i < c; i++)
{
my_abs2(1);
my_abs2(-1);
}
end_time = clock();
std::cout << static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << std::endl;
}
结果:9406、11442、11318
最终两种快速运算绝对值的函数反而使用时间更久,于是我直接计算而不调用函数:
int main()
{
int c = 1000000000;
clock_t start_time = clock();
for (int i = 0; i < c; i++)
{
abs(1);
abs(-1);
}
clock_t end_time = clock();
std::cout << static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << std::endl;
start_time = clock();
for (int i = 0; i < c; i++)
{
(1 ^ (1 >> 31)) - (1 >> 31);
(-1 ^ (-1 >> 31)) - (-1 >> 31);
}
end_time = clock();
std::cout << static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << std::endl;
start_time = clock();
for (int i = 0; i < c; i++)
{
1* (1 - (1 >> 31) << 1);
-1* (1 - (-1 >> 31) << 1);
}
end_time = clock();
std::cout << static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << std::endl;
}
结果为:9366、2145、2147。
可以得出这两种方法确实更快,但是第一次测试我使用了__forceinline也使用了引用为实参,为什么会满那么多?而且对比的对象是普通的C++abs函数,都是函数调用,为什么代价这么大?
#我正在寻找最快速的求绝对值方法,是否有int和float的快速求绝对值方法?
该回答引用ChatGPT-3.5,仅供参考,不保证完全正确
首先,关于你的第一个问题,为什么使用__forceinline
和引用参数对于这两种快速求绝对值的函数没有产生性能提升。在C++中,使用__forceinline
关键字可以提示编译器尝试将函数内联展开,以减少函数调用的开销。然而,编译器是否实际进行内联展开,还取决于编译器的具体实现和优化设置。
在你的测试中,你使用了clock()
函数来测量函数调用的时间开销。然而,clock()
函数并不是一个精确的计时器,而且在不同的编译器和平台上可能会有不同的行为。因此,通过clock()
函数来测量函数调用的性能差异可能并不准确。
此外,现代编译器在进行优化时,通常会对常见的函数调用进行内联展开,如abs()
函数。因此,在你的测试中,对于简单的函数调用,编译器可能已经进行了适当的内联展开,使得性能与手动展开的函数相当。
至于你的第二个问题,如何更快地计算int和float类型的绝对值,这里有一些常见的方法:
对于int类型,可以使用位操作和条件判断来计算绝对值,例如:
int abs(int value) {
int mask = value >> (sizeof(int) * CHAR_BIT - 1);
return (value + mask) ^ mask;
}
这种方法利用了整数的符号位来生成一个掩码,然后将掩码与原始值相加,再异或掩码,即可得到绝对值。
对于float类型,可以使用union和位操作来计算绝对值,例如:
float abs(float value) {
union {
float f;
uint32_t i;
} u;
u.f = value;
u.i &= 0x7FFFFFFF; // 将符号位置0
return u.f;
}
这种方法通过将float类型的值视为32位整数,并将符号位置0来得到绝对值。
需要注意的是,以上方法可能在不同的平台和编译器上产生不同的结果,且性能差异可能不明显。对于绝对值这样的简单操作,现代的编译器通常已经对其进行了高度优化,因此手动优化可能带来的性能提升可能是微乎其微的。如果性能是你的主要关注点,建议使用编译器优化选项,如-O2或-O3,让编译器自行处理这些优化。
总结来说,对于简单的函数调用,编译器通常能够进行适当的优化,因此手动展开函数可能不会带来明显的性能提升。同时,现代的编译器已经对常见的操作进行了高度优化,手动优化的效果可能有限。如果性能是关键需求,建议使用编译器的优化选项,并进行基于实际测试的性能优化。
该回答引用NewBing,仅供参考,不保证完全正确
__forceinline是一个编译器特定的关键字,用于强制将函数内联,即将函数的代码直接插入到调用点,而不是通过函数调用的方式执行。这样可以减少函数调用的开销,提高程序的运行速度。但是,__forceinline并不保证一定会内联,编译器可能会根据其他因素决定是否内联。__forceinline也可能导致代码体积增大,缓存命中率降低等问题。__forceinline是一个非标准的扩展,不同的编译器可能有不同的实现和语法。¹²
求绝对值的方法有很多种,不同的方法可能在不同的平台和场景下有不同的效率。一般来说,求绝对值的方法可以分为以下几类:
x > 0 ? x : -x
或if (x > 0) return x; else return -x;
,这些方法可能会引入分支预测错误的开销,但也可能被编译器优化为条件传送指令,无分支。⁴(x ^ (x >> 31)) - (x >> 31)
或x * (1 - (x >> 31) << 1)
,这些方法可以避免分支,但也可能引入其他开销,如移位、异或、乘法等。⁵要确定哪种方法最快,最好是在目标平台上进行实际的测试和比较,并考虑数据分布、编译器优化、缓存效果等因素。
¹: inline vs __inline vs inline vs __forceinline? - Stack Overflow
²: How to #define __forceinline inline? - Stack Overflow
³: abs(3) - Linux manual page
⁴: C语言里求绝对值最快的办法是什么? - 知乎
⁵: C语言里求绝对值最快的办法是什么? - 知乎
⁶: C语言里求绝对值最快的办法是什么? - 知乎
源: 与必应的对话, 2023/7/18
(1) inline vs __inline vs inline vs __forceinline? - Stack Overflow. https://stackoverflow.com/questions/2765164/inline-vs-inline-vs-inline-vs-forceinline.
(2) gcc - How to #define __forceinline inline? - Stack Overflow. https://stackoverflow.com/questions/8897791/how-to-define-forceinline-inline.
(3) __forceinline 内联函数_残月飞雪的博客-CSDN博客. https://blog.csdn.net/majinlei121/article/details/46118749.
(4) 1.1.2 Java @ForceInline 注解用法_扶朕去网吧的博客-CSDN博客. https://blog.csdn.net/pxg943055021/article/details/125430078.
(5) C语言里求绝对值最快的办法是什么? - 知乎. https://www.zhihu.com/question/23536224.
(6) Excel计算数值绝对值的2种操作方法 - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/557463959.
(7) inline vs __inline vs inline vs __forceinline? - Stack Overflow. https://stackoverflow.com/questions/2765164/inline-vs-inline-vs-inline-vs-forceinline.
(8) gcc - How to #define __forceinline inline? - Stack Overflow. https://stackoverflow.com/questions/8897791/how-to-define-forceinline-inline.
(9) C语言里求绝对值最快的办法是什么? - 知乎. https://www.zhihu.com/question/23536224.
(10) C语言里求绝对值最快的办法是什么? - 知乎. https://www.zhihu.com/question/23536224.
(11) C语言里求绝对值最快的办法是什么? - 知乎. https://www.zhihu.com/question/23536224.
(12) Excel表格中怎么使用公式快速求数值的绝对值? - 脚本之家. https://www.jb51.net/office/excel/502432.html.
(13) undefined. http://msdn.microsoft.com/en-us/library/z8y1yy88%28VS.71%29.aspx.