通过编码是否有任何(非微优化)性能增益
float f1 = 200f / 2
Run Code Online (Sandbox Code Playgroud)
在比较中
float f2 = 200f * 0.5
Run Code Online (Sandbox Code Playgroud)
几年前我的一位教授告诉我,浮点除法比浮点乘法慢,但没有详细说明原因.
这句话适用于现代PC架构吗?
UPDATE1
关于评论,请同时考虑这个案例:
float f1;
float f2 = 2
float f3 = 3;
for( i =0 ; i < 1e8; i++)
{
f1 = (i * f2 + i / f3) * 0.5; //or divide by 2.0f, respectively
}
Run Code Online (Sandbox Code Playgroud)
更新2 从评论中引用:
[我想]知道什么是算法/架构要求导致>除法在硬件上比复制要复杂得多
我发现了这个有趣且功能强大的工具IACA(英特尔架构代码分析器),但我无法理解它.我能用它做什么,它的局限性是什么?我该怎么做:
我正在尝试优化一些矩阵计算,我想知道是否有可能在编译时检测SSE/SSE2/AVX/AVX2/AVX-512/AVX-128-FMA/KCVI [1]是否由编译器?理想情况下,对于GCC和Clang,但我只能管理其中一个.
我不确定它是否可能,也许我将使用自己的宏,但我更愿意检测它并要求用户选择它.
[1] "KCVI"代表骑士角矢量指令优化.像FFTW这样的库检测/利用这些较新的指令优化.
我正在尝试快速的Exp(x)函数,这个函数之前在这个回答中描述了一个提高C#计算速度的SO问题:
public static double Exp(double x)
{
var tmp = (long)(1512775 * x + 1072632447);
return BitConverter.Int64BitsToDouble(tmp << 32);
}
Run Code Online (Sandbox Code Playgroud)
表达式使用一些IEEE浮点"技巧",主要用于神经集.该功能比常规Math.Exp(x)功能快约5倍.
不幸的是,相对于常规Math.Exp(x)函数,数值精度仅为-4% - + 2%,理想情况下,我希望精度至少在亚百分比范围内.
我已经绘制了近似和常规Exp函数之间的商,并且从图中可以看出,相对差异似乎以几乎恒定的频率重复.

是否有可能利用这种规律性来进一步提高"快速exp"功能的准确性而不会显着降低计算速度,或者精度提高的计算开销是否会超过原始表达式的计算增益?
(作为旁注,我也尝试过在同一个SO问题中提出的替代方法之一,但这种方法在C#中似乎没有计算效率,至少在一般情况下并非如此.)
5月14日更新
根据@Adriano的要求,我现在已经执行了一个非常简单的基准测试.我已经使用每个替代exp函数对[-100,100]范围内的浮点值执行了1000万次计算.由于我感兴趣的值范围从-20到0,我还明确列出了x = -5处的函数值.结果如下:
Math.Exp: 62.525 ms, exp(-5) = 0.00673794699908547
Empty function: 13.769 ms
ExpNeural: 14.867 ms, exp(-5) = 0.00675211846828461
ExpSeries8: 15.121 ms, exp(-5) = 0.00641270968867667
ExpSeries16: 32.046 ms, exp(-5) = 0.00673666189488182
exp1: 15.062 ms, exp(-5) = -12.3333325982094
exp2: 15.090 …Run Code Online (Sandbox Code Playgroud) 对于没有内置浮点三角学的机器,我需要一个相当准确的快速双曲正切,因此例如通常的tanh(x) = (exp(2x) - 1) / (exp(2x) + 1)公式将需要近似值exp(2x)。
\n所有其他指令,如加法、减法、乘法、除法,甚至 FMA(= 1 次操作中的 MUL+ADD)都存在。
现在我有几个近似值,但没有一个在准确性方面令人满意。
\n[评论更新:]
\ntrunc()/的说明floor()可用精度:\xc2\xb11.2% 绝对误差,请参见此处。
\n伪代码(A = 累加器寄存器,T = 临时寄存器):
\n[1] FMA T, 36.f / 73.f, A, A // T := 36/73 + X^2\n[2] MUL A, A, T // A := X(36/73 …Run Code Online (Sandbox Code Playgroud) 我正在做一些统计计算.我需要它们快速,所以我重写了大部分内容以使用SSE.我对它很陌生,所以我想知道这里的正确方法是什么:
据我所知,SSE中没有log2或ln功能,至少不能达到4.1,这是我使用的硬件支持的最新版本.
是否更好:
我有以下代码,并期望使用函数的内在版本exp().不幸的是,它不是在x64版本中,使其比类似的Win32(即32位版本)慢:
#include "stdafx.h"
#include <cmath>
#include <intrin.h>
#include <iostream>
int main()
{
const int NUM_ITERATIONS=10000000;
double expNum=0.00001;
double result=0.0;
for (double i=0;i<NUM_ITERATIONS;++i)
{
result+=exp(expNum); // <-- The code of interest is here
expNum+=0.00001;
}
// To prevent the above from getting optimized out...
std::cout << result << '\n';
}
Run Code Online (Sandbox Code Playgroud)
我正在使用以下开关进行构建:
/Zi /nologo /W3 /WX-
/Ox /Ob2 /Oi /Ot /Oy /GL /D "WIN32" /D "NDEBUG"
/D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm-
/EHsc /GS /Gy /arch:SSE2 /fp:fast /Zc:wchar_t /Zc:forScope …Run Code Online (Sandbox Code Playgroud) c++ visual-studio-2010 intrinsics visual-c++ visual-c++-2010
我正在寻找在AVX元件(单精度浮点)上运行的指数函数的有效(快速)近似.即 - __m256 _mm256_exp_ps( __m256 x )没有SVML.
相对精度应该类似于~1e-6,或~20个尾数位(1 ^ 2 ^ 20).
如果用英特尔内在函数用C风格编写,我会很高兴.
代码应该是可移植的(Windows,macOS,Linux,MSVC,ICC,GCC等).
这类似于使用SSE的指数函数的最快实现,但是这个问题寻求非常快速且精度低(当前的答案提供了大约1e-3的精度).
此外,这个问题是寻找AVX/AVX2(和FMA).但请注意,这两个问题的答案很容易在SSE4 __m128或AVX2 之间移植__m256,因此未来读者应根据所需的精度/性能权衡进行选择.
我正在寻找快速SSE低精度(~1e-3)指数函数.
我遇到了这个很好的答案:
/* max. rel. error = 3.55959567e-2 on [-87.33654, 88.72283] */
__m128 FastExpSse (__m128 x)
{
__m128 a = _mm_set1_ps (12102203.0f); /* (1 << 23) / log(2) */
__m128i b = _mm_set1_epi32 (127 * (1 << 23) - 298765);
__m128i t = _mm_add_epi32 (_mm_cvtps_epi32 (_mm_mul_ps (a, x)), b);
return _mm_castsi128_ps (t);
}
Run Code Online (Sandbox Code Playgroud)
根据Nicol N. Schraudolph的工作:NN Schraudolph."指数函数的快速,紧凑近似." Neural Computation,11(4),1999年5月,pp.853-862.
现在我需要一个"双精度"版本:__m128d FastExpSSE (__m128d x).这是因为我不控制输入和输出精度,这恰好是双精度,并且两次转换double - > float,then float - > double占用了50%的CPU资源.
需要做哪些改变?
我天真地试过这个:
__m128i double_to_uint64(__m128d x) { …Run Code Online (Sandbox Code Playgroud) 下面是我想要转换的代码:该double版本的VDT的帕德精通fast_ex()约(这里的老回购资源):
inline double fast_exp(double initial_x){
double x = initial_x;
double px=details::fpfloor(details::LOG2E * x +0.5);
const int32_t n = int32_t(px);
x -= px * 6.93145751953125E-1;
x -= px * 1.42860682030941723212E-6;
const double xx = x * x;
// px = x * P(x**2).
px = details::PX1exp;
px *= xx;
px += details::PX2exp;
px *= xx;
px += details::PX3exp;
px *= x;
// Evaluate Q(x**2).
double qx = details::QX1exp;
qx *= xx;
qx += details::QX2exp;
qx …Run Code Online (Sandbox Code Playgroud) After reading this question, I'm wondering what happens under the hood when np.exp is called: what is the mathematical/numerical routine used to derive the values in the returned array? For example, I think that to compute np.sqrt(x), a solution in y to y ** 2 - x = 0 is found using Newton's method.
(np.exp 的文档字符串没有说明这是如何完成的)
我正在制作一个基本上利用SSE2优化此代码的代码:
double *pA = a;
double *pB = b[voiceIndex];
double *pC = c[voiceIndex];
for (int sampleIndex = 0; sampleIndex < blockSize; sampleIndex++) {
pC[sampleIndex] = exp((mMin + std::clamp(pA[sampleIndex] + pB[sampleIndex], 0.0, 1.0) * mRange) * ln2per12);
}
Run Code Online (Sandbox Code Playgroud)
在这:
double *pA = a;
double *pB = b[voiceIndex];
double *pC = c[voiceIndex];
// SSE2
__m128d bound_lower = _mm_set1_pd(0.0);
__m128d bound_upper = _mm_set1_pd(1.0);
__m128d rangeLn2per12 = _mm_set1_pd(mRange * ln2per12);
__m128d minLn2per12 = _mm_set1_pd(mMin * ln2per12);
__m128d loaded_a = _mm_load_pd(pA);
__m128d loaded_b = _mm_load_pd(pB); …Run Code Online (Sandbox Code Playgroud)