为实数提供动力的最快方法是什么?

问题描述 投票:0回答:2

我当然知道cmath(math.h)中有一个很好的pow()函数,但不接触pow()的背景什么是最快的方法来计算数字用我自己的双手

c++ algorithm mathematical-optimization
2个回答
2
投票

您在问两个不同的问题:

  • 为实数提供动力的最快方法是什么?
  • 用自己的双手为数字提供动力的最快方法是什么?

这些有不同的答案。

pow
很快。标准库的实现通常由非常聪明的人编写,由其他聪明的人审查,然后由更聪明的人重构。因此,使用提供的标准库实现几乎总是比尝试自己重新实现标准库更好。

但是,如果您坚持创建自己的

pow
实现,则应首先使用泰勒级数展开来实现
exp
log
。然后使用以下属性:

pow(base,power) = exp( power * log(base) )

请注意,如果

base
为负数,则应首先计算
pow(-base,power)
,然后对
base
进行奇偶校验以确定结果的符号。


0
投票

在我的系统中,Visual Studio 中的标准 pow() 函数的运行速度比我使用 x87 指令编写的简单函数几乎慢 1.4 倍。但我努力工作,使用 AVX 指令编写了几乎同样精确的函数,它的运行速度比标准 pow() 快约 2.5 倍。下面我提供了两个版本的代码(x86架构)。

FPU代码

_declspec(naked) double _fastcall pwr(const double &x, const double &y)
{
  _asm
  {
    fld qword ptr [edx] // Load exponent y
    fld qword ptr [ecx] // Load base x
    fyl2x               // Calculate y*lb(x). This will throw an error if x<0
    fxam                // Check result type to reveal values +-Inf
    fnstsw ax           // Move the swr register into ax (there is the check result)
    sahf                // Set cf if y*lb(x) is equal +-Inf or NaN
    fld1                // On stack: y*lb(x); 1
    fld st(1)           // On stack: y*lb(x); 1; y*lb(x)
    frndint             // В st(0) - exponent rounded to whole numbers (yi)
    fsub st(2),st(0)    // в st(2) - fraction of yf in the range from -0.5 to 0.5
    fxch st(2)          // On stack: yi; 1; yf
    fcmovb st(0),st(1)  // In case |y*lb(x)|=Inf replace yf (equal NaN) by 1
    f2xm1               // Calculate 2^yf-1
    faddp st(1),st(0)   // Add 1 to result, we get 2^yf
    fscale              // Take into account the whole part by scaling
    fstp st(1)          // Remove yi from stack, результат в st(0)
    ret                 // Return
  }
}

AVX 代码 (稍后会...)

© www.soinside.com 2019 - 2024. All rights reserved.