Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否仍然值得尝试在C中为sqrt()创建优化?_C_Performance_Optimization - Fatal编程技术网

是否仍然值得尝试在C中为sqrt()创建优化?

是否仍然值得尝试在C中为sqrt()创建优化?,c,performance,optimization,C,Performance,Optimization,创建更快的sqrt()实现的旧技巧(查找表、近似函数)是否仍然有用,或者默认实现是否与现代编译器和硬件一样快?sqrt在大多数系统上基本不变。这是一个相对缓慢的操作,但总体系统速度有所提高,因此可能不值得尝试使用“技巧” 决定优化它与近似(小)收益,这可以实现真正取决于你。现代硬件已经消除了一些牺牲(速度与精度)的需要,但在某些情况下,这仍然是有价值的 我将使用评测来确定这是否“仍然有用”。如果您已经证明代码中对sqrt()的调用是评测器的瓶颈,那么尝试创建优化版本可能是值得的。否则就是浪费时间

创建更快的sqrt()实现的旧技巧(查找表、近似函数)是否仍然有用,或者默认实现是否与现代编译器和硬件一样快?

sqrt在大多数系统上基本不变。这是一个相对缓慢的操作,但总体系统速度有所提高,因此可能不值得尝试使用“技巧”

决定优化它与近似(小)收益,这可以实现真正取决于你。现代硬件已经消除了一些牺牲(速度与精度)的需要,但在某些情况下,这仍然是有价值的


我将使用评测来确定这是否“仍然有用”。

如果您已经证明代码中对sqrt()的调用是评测器的瓶颈,那么尝试创建优化版本可能是值得的。否则就是浪费时间。

规则1:优化前的配置文件 在相信自己可以打败优化器之前,您必须分析所有内容,并找出瓶颈所在。一般来说,
sqrt()
本身不太可能是您的瓶颈

规则2:在替换标准函数之前替换算法 即使
sqrt()
是瓶颈,那么仍然有可能存在算法方法(例如按长度平方排序距离,无需调用任何数学函数即可轻松计算),可以从一开始就消除调用
sqrt()
的需要

如果您不做其他事情,编译器会为您做什么 许多现代C编译器愿意以更高的优化级别内联CRT函数,使自然表达式(包括对
sqrt()
的调用)尽可能快

特别是,我检查了MinGW gcc v3.4.5,它用改变FPU状态的内联代码替换了对
sqrt()
的调用,并在核心使用了
FSQRT
指令。由于C标准与IEEE 754浮点交互的方式,它必须遵循
FSQRT
,使用一些代码检查异常情况,并从运行库调用real
sqrt()
函数,以便库可以根据标准的要求处理浮点异常

使用
sqrt()
内联,并在更大的all
double
表达式的上下文中使用,在满足标准要求和保持完全精度的约束条件下,结果尽可能有效

对于编译器和目标平台的这种(非常常见的)组合,在不了解用例的情况下,这个结果非常好,代码清晰且可维护

在实践中,任何技巧都会使代码变得不那么清晰,并且很可能不易维护。毕竟,您更愿意维护
(-b+sqrt(b*b-4.*a*c))/(2*a)
还是一个不透明的内联程序集和表块

此外,在实践中,您通常可以指望编译器和库作者充分利用平台的功能,并且通常比您更了解优化的微妙之处

然而,在极少数情况下,可以做得更好

其中一种情况是在计算中,您知道自己真正需要多少精度,也知道自己不依赖于C标准的浮点异常处理,而是能够适应硬件平台提供的功能

编辑:我重新安排了文本,以强调乔纳森·莱夫勒在评论中建议的分析和算法。谢谢你,乔纳森


Edit2:修复了由用户锐利的眼睛发现的二次示例中的优先级键入错误。

为什么不?你可能学到了很多

由于现代计算机的设计方式,我很难相信sqrt函数是应用程序的瓶颈。假设这不是一个关于某个疯狂的低端处理器的问题,那么在访问CPU缓存之外的内存时,你会受到巨大的速度冲击,因此,除非你的算法只对少数几个数字进行计算(足够使它们基本上都适合L1和L2缓存)您不会注意到优化任何算术运算的任何速度。

通常可以安全地假设标准库开发人员非常聪明,并且编写了性能良好的代码。总的来说,你不太可能与它们相匹配

所以问题变成了,你知道什么能让你做得更好吗?我不是在问计算平方根的特殊算法(标准库开发人员也知道这些算法,如果它们在总体上是值得的,他们已经使用过了),但是您是否有任何关于您的用例的特定信息,可以改变这种情况

你只需要有限的精度吗?如果是这样的话,与标准库版本相比,您可以加快速度,标准库版本必须准确

或者您知道您的应用程序将始终在特定类型的CPU上运行吗?然后,您可以查看CPU的sqrt指令的效率,并查看是否有更好的替代方案。当然,这样做的缺点是,如果我在另一个CPU上运行你的应用程序,你的代码可能会比标准的sqrt()慢

您能在代码中做出标准库开发人员无法做到的假设吗

对于“实现对标准库sqrt的有效替换”这一问题,您不太可能找到更好的解决方案


但是,您可能会想出一个解决方案来解决“针对这种特定情况实施有效的平方根函数”的问题。

这可能是计算平方根的最快方法:

float fastsqrt(float val)  {
        union
        {
                int tmp;
                float val;
        } u;
        u.val = val;
        u.tmp -= 1<<23; /* Remove last bit so 1.0 gives 1.0 */
        /* tmp is now an approximation to logbase2(val) */
        u.tmp >>= 1; /* divide by 2 */
        u.tmp += 1<<29; /* add 64 to exponent: (e+127)/2 =(e/2)+63, */
        /* that represents (e/2)-64 but we want e/2 */
        return u.val;
}
这大约是
(float)(1.0/sqrt(x))

float InvSqrt (float x)
{
    float xhalf = 0.5f*x;
    int i = *(int*)&x;
    i = 0x5f3759df - (i>>1);
    x = *(float*)&i;
    return x*(1.5f - xhalf*x*x);
}