nuget server logo nuget api documents
↑

API Docs / Microsoft.VisualBasic.Runtime / SIMDIntrinsics

SIMDIntrinsics

Full name Microsoft.VisualBasic.Math.SIMD.SIMDIntrinsics Assembly Microsoft.VisualBasic.Runtime Members 14

基于 System.Runtime.Intrinsics.X86 的指令级融合内核。

00 Remarks

这里的函数都只负责“Double 与 Single 的 256 位 融合乘加(FMA)”这一类确实存在指令级收益的场景;普通的逐元素加减乘除 请使用 SimdEngine —— 因为 Vector256(Of Double) 的宽度 与 Vector(Of Double).Count 完全一致,再单独写一条 256 位路径只会 增加代码量而不会提升吞吐。

所有的 FMA 内核都会在运行期同时检查 SimdCapabilities.IsFma 与 SIMDEnvironment.IsEnabled:前者保证处理器确实有 FMA 指令, 后者保证 SIMDConfiguration.disable 这个全局逃生开关依然有效。 任一条件不满足时会退回到等价的 SimdEngine / SimdReduce 实现,因此这些函数在任何平台与任何配置下都是安全的。

与旧实现的关键差别:这里使用批量装载/存储 (New Vector256(Of T)(array, offset) + Vector256(Of T).CopyTo) 取代旧版的 Vector256.Create(...) 逐元素构造 + GetElement 逐元素回写(后者会因为多次插入/提取通道而失去向量化的全部收益)。

01 Syntax

Microsoft.VisualBasic.Math.SIMD.SIMDIntrinsics

02 Methods

NameOverloadsSummary
HorizontalSum4 1 Double 的 4 通道水平求和。
Load4 1 从 Double 数组的 offset 处批量装载一个 256 位向量。
Load8 1 从 Single 数组的 offset 处批量装载一个 256 位向量。
Store4 1 把一个 256 位向量批量写回 Double 数组。
VectorAddAvx 2 逐元素相加(Double)。
VectorAddAvx2 2 逐元素相加(Double)。
DotFma 2 点积(Double),使用 FMA 融合乘加。
SumSquaresFma 1 平方和:SUM(v(i) ^ 2),使用 FMA 融合乘加。
Axpy 1 AXPY:out(i) = alpha * x(i) + y(i),使用 FMA 融合乘加。
AxpyInPlace 1 就地 AXPY:y(i) += alpha * x(i),使用 FMA 融合乘加。
MultiplyAdd 1 融合乘加:out(i) = v1(i) * v2(i) + acc(i)

03 Members

method HorizontalSum4 #
HorizontalSum4(Vector256(Of Double))

Double 的 4 通道水平求和。

method Load4 #
Load4(Double(), Int32)

从 Double 数组的 offset 处批量装载一个 256 位向量。

method Load8 #
Load8(Single(), Int32)

从 Single 数组的 offset 处批量装载一个 256 位向量。

method Store4 #
Store4(Vector256(Of Double), Double(), Int32)

把一个 256 位向量批量写回 Double 数组。

method VectorAddAvx #
VectorAddAvx(Double(), Double())

逐元素相加(Double)。

Remarks

保留这个名称仅为兼容旧代码;内部走 SimdEngine.Add() 这条跨平台的主干路径。

method VectorAddAvx overload 2 #
VectorAddAvx(Single(), Single())

逐元素相加(Single)。

method VectorAddAvx2 #
VectorAddAvx2(Double(), Double())

逐元素相加(Double)。

Remarks

保留这个名称仅为兼容旧代码;对 Double 而言 AVX2 与 AVX 的浮点加法是同一条指令,因此与 SIMDIntrinsics.VectorAddAvx() 完全等价。

method VectorAddAvx2 overload 2 #
VectorAddAvx2(Single(), Single())

逐元素相加(Single)。

method DotFma #
DotFma(Double(), Double())

点积(Double),使用 FMA 融合乘加。

Remarks

与 SIMDIntrinsics.SumSquaresFma() 一样使用 4 路独立累加器来打断 FMA 的依赖链;归约顺序不同会带来 ULP 级差异。

Parameters
NameTypeDescription
v1Double()

-

v2Double()

-

Returns

SUM(v1(i) * v2(i))

method DotFma overload 2 #
DotFma(Single(), Single())

点积(Single),使用 FMA 融合乘加并以 Double 累加。

method SumSquaresFma #
SumSquaresFma(Double())

平方和:SUM(v(i) ^ 2),使用 FMA 融合乘加。

Remarks

使用 4 路独立累加器:FMA 的延时约为 4 个周期,若只用一个累加器, 整个循环会被这条依赖链串行化,吞吐无法超过「1 条 FMA / 4 周期」; 4 路累加器让乱序执行可以同时保持多条 FMA 在飞,长数组上能拿到接近 3~4 倍的额外提升(这也是 SimdReduce.SumSquares() 采用同样策略的原因)。

归约顺序与单累加器版本不同,因此结果可能存在浮点末位(ULP)级差异。

method Axpy #
Axpy(Double, Double(), Double())

AXPY:out(i) = alpha * x(i) + y(i),使用 FMA 融合乘加。

method AxpyInPlace #
AxpyInPlace(Double, Double(), Double())

就地 AXPY:y(i) += alpha * x(i),使用 FMA 融合乘加。

Remarks

这是矩阵分解/求解器里出现频率最高的一类 BLAS-1 操作(列消元、Gram-Schmidt 正交化、秩一更新的行部分),就地更新可以避免为每次迭代分配临时数组。

为什么不使用“末块与末尾重叠”的技巧:输入与输出共用同一块内存, 重叠部分会把已经更新过的元素再算一次,因此尾块退化为单通道逐元素计算。

method MultiplyAdd #
MultiplyAdd(Double(), Double(), Double())

融合乘加:out(i) = v1(i) * v2(i) + acc(i)