什么比std::pow快?
What is faster than std::pow?
我的程序在std::pow(double,int)
函数上花费了90%的CPU时间。准确性不是这里的主要关注点,所以我想知道是否有更快的替代方案。我想尝试的一件事是铸造浮动,执行操作,然后回到双(还没有尝试过);我担心这不是一种提高性能的可移植方式(大多数cpu不是本质上对双精度操作吗?)
欢呼
看起来像Martin Ankerl有一些关于这方面的文章,优化近似pow()在C/c++中是一个,它有两个快速版本,一个如下:
inline double fastPow(double a, double b) {
union {
double d;
int x[2];
} u = { a };
u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447);
u.x[0] = 0;
return u.d;
}
依赖于通过联合的类型双关语,这是c++中未定义的行为,来自标准草案9.5
[class.union]:
在union中,任何时候最多只能有一个非静态数据成员处于活动状态,即at的值大多数非静态数据成员可以随时存储在联合中。[…]
但是包括GCC在内的大多数编译器都支持这个定义良好的行为:
从不同于最近写入的联合成员(称为"类型双关语")中读取的做法很常见。即使使用- strict-aliasing,只要通过联合类型
访问内存,也允许使用类型双关语。
但这并不普遍,正如本文所指出的,正如我在这里的回答中所指出的,使用memcpy
应该生成相同的代码,并且不会调用未定义的行为。
他还链接到第二个针对Java、C/c++和c#的优化pow()近似。
第一篇文章还链接到他的微基准测试
根据您需要做的事情,在对数域中操作可能会起作用-也就是说,您将所有值替换为它们的对数;乘法变成加法,除法变成减法,取幂变成乘法。但是现在加法和减法变得昂贵并且有些容易出错。
你的整数有多大?它们在编译时是已知的吗?将x^2
计算为x*x
而不是pow(x,2)
要好得多。注意:几乎所有pow()
的整数次幂的应用都涉及到一些数的二次或三次幂(或者在负指数的情况下的乘法逆)。在这种情况下使用pow()
是多余的。使用一个模板来处理这些小的整数幂,或者直接使用x*x
。
如果整数很小,但在编译时不知道,比如在-12和+12之间,乘法仍然会胜过pow()
,并且不会失去精度。你不需要11次乘法来计算x^12。四个就行了。使用这一事实x ^ (2 n) = (x ^ n) ^ 2 x ^ (2 n + 1) = x * ((x ^ n) ^ 2)。例如,x^12等于((x*x*x)^2)^2。两次乘法计算x^3 (x*x*x),再一次乘法计算x^6,最后一次乘法计算x^12。
YES!非常快,如果你只需要'y'/'n'作为一个长/int,这允许你避免缓慢的FPU FSCALE函数。这是Agner Fog的x86手动优化版本,如果你只需要'y'/'n'作为INT的结果。为了速度/大小,我将其升级为__fastcall/__declspec(裸),使用ECX传递'n'(浮点数总是在32位msvc++的堆栈中传递),所以对我来说非常小的调整,这主要是Agner的工作。它是在MS Visual vc++ 2005 Express/Pro上测试/调试/编译的,所以应该可以在较新的版本中插入。相对于通用CRT的pow()函数,精度非常好。
extern double __fastcall fs_power(double x, long n);
// Raise 'x' to the power 'n' (INT-only) in ASM by the great Agner Fog!
__declspec(naked) double __fastcall fs_power(double x, long n) { __asm {
MOV EAX, ECX ;// Move 'n' to eax
;// abs(n) is calculated by inverting all bits and adding 1 if n < 0:
CDQ ;// Get sign bit into all bits of edx
XOR EAX, EDX ;// Invert bits if negative
SUB EAX, EDX ;// Add 1 if negative. Now eax = abs(n)
JZ RETZERO ;// End if n = 0
FLD1 ;// ST(0) = 1.0 (FPU push1)
FLD QWORD PTR [ESP+4] ;// Load 'x' : ST(0) = 'x', ST(1) = 1.0 (FPU push2)
JMP L2 ;// Jump into loop
L1: ;// Top of loop
FMUL ST(0), ST(0) ;// Square x
L2: ;// Loop entered here
SHR EAX, 1 ;// Get each bit of n into carry flag
JNC L1 ;// No carry. Skip multiplication, goto next
FMUL ST(1), ST(0) ;// Multiply by x squared i times for bit # i
JNZ L1 ;// End of loop. Stop when nn = 0
FSTP ST(0) ;// Discard ST(0) (FPU Pop1)
TEST EDX, EDX ;// Test if 'n' was negative
JNS RETPOS ;// Finish if 'n' was positive
FLD1 ;// ST(0) = 1.0, ST(1) = x^abs(n)
FDIVR ;// Reciprocal
RETPOS: ;// Finish, success!
RET 4 ;//(FPU Pop2 occurs by compiler on assignment
RETZERO:
FLDZ ;// Ret 0.0, fail, if n was 0
RET 4
}}
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 警告处理为错误这里有什么问题
- 什么时候调用组成单元对象的析构函数
- #定义c-预处理器常量..我做错了什么
- 努力将整数转换为链表。不知道我在这里做错了什么
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 什么时候在C++中返回常量引用是个好主意
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- C++避免重复声明的语法是什么
- c++库的公共头文件中应该包含什么
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- ifstream什么都没读
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 循环c 时,此POW()在功能中起到了什么作用
- nan在C++中是什么意思?为什么pow(-4,-2.1)返回-nan
- 标准对std::pow、std::log等cmath函数有什么规定?
- 什么比std::pow快?
- 用pow(x,2)代替x*x有什么好处吗