单目(逐元素一元)向量化的数学函数。
SimdMath
00 Remarks
设计说明:只有存在对应硬件指令的运算才会被向量化。 SimdMath.Sqrt()/SimdMath.Abs()/SimdMath.Negate()/SimdMath.Square()/SimdMath.Clamp()/ SimdMath.Reciprocal() 都可以直接映射到 Vector 原语; 而 SimdMath.Exp() 与 SimdMath.Log() 在主流 x86/ARM 处理器上没有逐元素硬件指令 (仅 AVX-512 的 ER/PF 子集提供近似指令,且精度与可用性都不足以作为默认实现), 因此这两个函数保持与 Math 完全一致的标量实现,以保证数值结果的 确定性;对它们做“看似向量化”的多项式逼近会静默牺牲精度,这里不做这种取舍。
01 Syntax
02 Methods
| Name | Overloads | Summary |
|---|---|---|
| Abs | 1 | 逐元素绝对值:out(i) = |v(i) |
| Negate | 1 | 逐元素取负:out(i) = -v(i) |
| Square | 1 | 逐元素平方:out(i) = v(i) ^ 2 |
| Sqrt | 2 | 逐元素平方根(Double)。 |
| Floor | 2 | 逐元素向下取整(Double):out(i) = Floor(v(i)) |
| Ceiling | 2 | 逐元素向上取整(Double):out(i) = Ceiling(v(i)) |
| Truncate | 2 | 逐元素截断取整(Double):out(i) = Truncate(v(i)) |
| Sign | 2 | 逐元素符号函数(Double): out(i) = If(v(i) > 0, 1, If(v(i) < 0, -1, v(i))) |
| Reciprocal | 2 | 逐元素倒数(Double):out(i) = 1 / v(i) |
| Clamp | 1 | 逐元素区间钳制:out(i) = Min(Max(v(i), min), max) |
| Pow | 1 | 逐元素幂运算:out(i) = v1(i) ^ v2(i) |
| PowScalar | 1 | 以固定指数求幂:out(i) = v(i) ^ exponent |
| Exp | 2 | 逐元素自然指数:out(i) = Exp(v(i)) |
| Log | 3 | 逐元素以 base 为底的对数:out(i) = Log(v(i), base)。 |
| Abs | 1 | |
| Negate | 1 | |
| Square | 1 | |
| Clamp | 1 |
03 Members
``0())逐元素绝对值:out(i) = |v(i)|
``0())逐元素取负:out(i) = -v(i)
``0())逐元素平方:out(i) = v(i) ^ 2
Double())逐元素平方根(Double)。
Single())逐元素平方根(Single)。
Double())逐元素向下取整(Double):out(i) = Floor(v(i))
Vector.Floor 会由 JIT 映射到 SSE4.1 的 roundpd / AVX 的 vroundpd,或者 ARM64 的 frintm,语义与 Math.Floor() 完全一致。
Single())逐元素向下取整(Single)。
Double())逐元素向上取整(Double):out(i) = Ceiling(v(i))
Single())逐元素向上取整(Single)。
Double())逐元素截断取整(Double):out(i) = Truncate(v(i))
Single())逐元素截断取整(Single)。
Double())逐元素符号函数(Double): out(i) = If(v(i) > 0, 1, If(v(i) < 0, -1, v(i)))
“既不大于零也不小于零”的通道直接输出原始值,因此 +0.0 / -0.0 与 Double 的返回值与 Math.Sign() 保持一致(NaN 输入得到 NaN,而不是被静默变成 0)。
Single())逐元素符号函数(Single)。
Double())逐元素倒数(Double):out(i) = 1 / v(i)
Single())逐元素倒数(Single):out(i) = 1 / v(i)
``0(), ``0, ``0)逐元素区间钳制:out(i) = Min(Max(v(i), min), max)
这个函数是手写展开的(而不是复用 SimdMath.Unary()), 以避免为了捕获 min / max 而产生闭包对象的堆分配。
Double(), Double())逐元素幂运算:out(i) = v1(i) ^ v2(i)
幂运算没有逐元素硬件指令(VB 的 ^ 会编译成 Math.Pow()),因此这里保持标量实现。 当指数是编译期可知的常量时,请优先使用 SimdMath.PowScalar() —— 它能够把 常见指数(2/3/4/0.5)特化为向量化的乘法与开方。
Double(), Double)以固定指数求幂:out(i) = v(i) ^ exponent
常见指数会被特化为向量化的乘法/开方:
0→ 常量 11→ 直接拷贝2→ SimdMath.Square()3→v * v * v4→ 连续两次 SimdMath.Square()0.5→ SimdMath.Sqrt()
其余指数退回标量 ^(与 VB 运算符语义完全一致)。
Double())逐元素自然指数:out(i) = Exp(v(i))
保持与 Math.Exp() 逐位一致的标量实现, 原因见类型备注(无可用硬件指令)。
Single())逐元素自然指数(Single)。
Double())逐元素自然对数:out(i) = Log(v(i))
保持与 Math.Log() 逐位一致的标量实现。
Single())逐元素自然对数(Single)。
Double(), Double)逐元素以 base 为底的对数:out(i) = Log(v(i), base)。
等价于 Log(v(i)) / Log(base),与 Math.Log() 的实现方式一致。 其中除法部分可以向量化,对数的预算仍然是标量(无硬件指令)。
T())T())T())T(), T, T)