- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我想利用可用的融合乘法加/减 CPU 指令来协助对适当大小的数组进行复杂的乘法运算。本质上,基础数学看起来像这样:
void ComplexMultiplyAddToArray(float* pDstR, float* pDstI, const float* pSrc1R, const float* pSrc1I, const float* pSrc2R, const float* pSrc2I, int len)
{
for (int i = 0; i < len; ++i)
{
const float fSrc1R = pSrc1R[i];
const float fSrc1I = pSrc1I[i];
const float fSrc2R = pSrc2R[i];
const float fSrc2I = pSrc2I[i];
// Perform complex multiplication on the input and accumulate with the output
pDstR[i] += fSrc1R*fSrc2R - fSrc1I*fSrc2I;
pDstI[i] += fSrc1R*fSrc2I + fSrc2R*fSrc1I;
}
}
正如您可能看到的那样,数据是结构化的,其中我们有单独的实数和虚数数组。现在,假设我有以下函数可用作分别执行 ab+c 和 ab-c 的单个指令的内部函数:
float fmadd(float a, float b, float c);
float fmsub(float a, float b, float c);
天真地,我可以看到我可以用一个 fmadd 和一个 fmsub 替换 2 个乘法、一个加法和一个减法,如下所示:
// Perform complex multiplication on the input and accumulate with the output
pDstR[i] += fmsub(fSrc1R, fSrc2R, fSrc1I*fSrc2I);
pDstI[i] += fmadd(fSrc1R, fSrc2I, fSrc2R*fSrc1I);
这会带来非常适度的性能改进,我假设还会提高准确性,但我认为我确实缺少一些可以对数学进行代数修改的东西,这样我就可以替换更多的 mult/add 或 mult/sub组合。在每一行中,都有一个额外的加法和一个额外的乘法,我觉得我可以将它们转换为单个 fma,但令人沮丧的是,我不知道如何在不改变操作顺序和得到错误结果的情况下做到这一点。有想法的数学专家吗?
就这个问题而言,目标平台可能并不那么重要,因为我知道这些类型的指令存在于各种平台上。
最佳答案
这是一个好的开始。你可以减少一个添加:
// Perform complex multiplication on the input and accumulate with the output
pDstR[i] += fmsub(fSrc1R, fSrc2R, fSrc1I*fSrc2I);
pDstI[i] += fmadd(fSrc1R, fSrc2I, fSrc2R*fSrc1I);
在这里你可以在虚部的计算中使用另一个fmadd
:
pDstI[i] = fmadd(fSrc1R, fSrc2I, fmadd(fSrc2R, fSrc1I, pDstI[i]));
同样,你可以对实部做同样的事情,但你需要否定这个论点。如果这会使事情变得更快或更慢,则在很大程度上取决于您正在处理的架构的微计时:
pDstR[i] = fmsub(fSrc1R, fSrc2R, fmadd(fSrc1I, fSrc2I, -pDstR[i]));
顺便说一句,如果您使用 restrict
关键字将目标数组声明为非别名,您可能会获得进一步的性能改进。现在编译器必须假定 pDstR 和 pDstI 可能重叠或指向同一 block 内存。这将阻止编译器在写入 pDstR[i] 之前加载 pDstI[i]。
如果编译器尚未执行此操作,则之后进行一些仔细的循环展开也可能有所帮助。检查编译器的汇编输出!
关于c++ - 使用 FMA(融合乘法)指令进行复数乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30089859/
我正在尝试比较 FMA 性能(math.h 中的 fma())与浮点计算中的朴素乘法和加法。测试很简单。我将为大迭代次数迭代相同的计算。要进行精确检查,我必须完成两件事。 计算时间不应包含其他计算。
根据documentation,在fma()中有一个math.h函数。很好,我知道FMA的工作原理以及使用目的。但是,我不确定这在实践中如何实现?我对x86和x86_64体系结构最感兴趣。 是否有FM
我有以下程序集(AT&T语法): mulsd %xmm0, %xmm1 addsd %xmm1, %xmm2 我想将其替换为: vfmadd231sd %xmm0, %xmm1, %xmm2
我想构建一个表示多个(比如 N)算术类型的数据类型,并提供与使用运算符重载的算术类型相同的接口(interface),这样我就可以得到像 Agner Fog 的 vectorclass 这样的数据类型
当我第一次获得 Haswell 处理器时,我尝试实现 FMA 来确定 Mandelbrot 集。主要算法是这样的: intn = 0; for(int32_t i=0; i= ab;
我正在分析一段线性代数代码,它是 calling intrinsics directly ,例如 v_dot0 = _mm256_fmadd_pd( v_x0, v_y0, v_dot0 ); 我的
我正在使用 Intel Haswell CPU 的 FMA 指令来优化一些计算。 但是,我发现即使我将 MXCSR 寄存器设置为 DNZ 和 FTZ 模式,这些指令也会生成异常。 我如何强制这些 FM
假设在某些 C 或 C++ 代码中我有一个名为 T fma( T a, T b, T c ) 的函数,它像这样执行 1 次乘法和 1 次加法 ( a * b) + c ;我应该如何优化多个 mul &
我想了解如何计算 FMA 性能。如果我们查看这里的描述: https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm2
使用中double fma(double x, double y, double z);我希望非零 d在下面标有 '?' 的输出行中.它似乎只在内部使用 long double精度而不是指定的无限精度
使用 Haswell 的 FMA 指令考虑以下指令序列: __m256 r1 = _mm256_xor_ps (r1, r1); r1 = _mm256_fmadd_ps (rp1, m6,
我看到过有关如何使用 FMA 指令集的问题,但在我开始使用它们之前,我首先想知道我是否可以(我的处理器是否支持它们)。我发现一篇文章说我需要查看(在 Linux 上工作)的输出: more /proc
我想了解如何最大限度地提高 CPU 上的操作次数。我正在做一个简单的矩阵乘法程序,我有一个 Skylake 处理器。我正在查看有关此架构的 flops 信息的维基百科页面,但我很难理解它。 据我了解,
我正在试验新的 FP 逻辑。唉,即使是与 FMA 相关的最简单的查询似乎也会给 z3 带来不少麻烦。 下面是一个这样的例子,我试图证明 x*y+0 等于 fma(x,y,0)。它做了一些额外的事情来确
我想利用可用的融合乘法加/减 CPU 指令来协助对适当大小的数组进行复杂的乘法运算。本质上,基础数学看起来像这样: void ComplexMultiplyAddToArray(float* pDst
我今天才注意到 Java 9 中存在 Math.fma(a, b, c),它计算 a*b + c (对于 double 和 float 值)。 Returns the fused multiply a
#include __m256 mult(__m256 num) { return 278*num/(num+1400); } .LCPI0_0: .long 0x438
我正在尝试修改一段使用 SSE(128 位)调用的代码,以使用 Bulldozer Opteron 上的 256 位 FMA 功能。我似乎无法找到这些调用的内在函数。 本论坛上的一些问题使用了这些内在
代码1: vzeroall mov rcx, 1000000 startLabel1: vfmadd231ps ymm0, ymm0, ymm0 vfmadd231ps
Z3 针对此基准测试返回了令人满意的模型:http://rise4fun.com/Z3/Bnv5m 但是,该查询本质上是断言 a*b+0 相当于使用 FMA 指令的 a*b,我相信这适用于 IEEE
我是一名优秀的程序员,十分优秀!