【问题标题】:Sum of elements in System.Numerics.Vector<T> in .NET 4.6.NET 4.6 中 System.Numerics.Vector<T> 中的元素总和
【发布时间】:2016-06-01 13:55:01
【问题描述】:

我不知道如何在 System.Numerics.Vector 类型的向量中获取元素总和。

double sum(System.Numerics.Vector<double> vect)
{
     // Something like 
     // double sum = 0;
     // foreach e in vect { sum += e; } 
     // return sum;

     // Vector.method???
     // For loop ???
}

如果真的有可能?我该怎么做?

【问题讨论】:

  • 众所周知,该类的理解很少,这也是它未添加到 .NET Framework 的原因。它代表一个 SIMD cpu 寄存器,可以存储 2 个双精度数或 4 个浮点数。它应该被命名为 SimdRegister。你真的打算创建一个包含任意数量元素的向量吗?
  • @stephen.vakil 似乎 OP 想要对向量的元素求和,而不是将其添加到另一个向量中。
  • 我同意@HansPassant 的观点,即您可能没有使用正确的数据结构。但是,如果您真的需要对元素求和,则必须执行 for 循环,因为它没有实现 IEnumerable
  • 我测试了它,它就像一个魅力。 JIT 还为它生成优化良好的内在函数。

标签: c# simd system.numerics


【解决方案1】:

假设您确实打算拥有一个Vector,它可能包含(在今天的硬件中)2 个或 4 个双精度数,这将对它们求和。

double vectorSum = Vector.Dot(yourDoubleVector, Vector<double>.One);

Dot 方法计算两个向量的点积,定义为大小为n 的两个向量ABA1 * B1 + A2 * B2 + ... + An * Bn

因此,向量A 和另一个全为 1 的向量的点积就是向量 A 中项目的总和。

【讨论】:

  • 不幸的是,JIT 相当愚蠢,在对结果进行随机/相加之前会进行实际的乘法运算。 (Writing a vector sum function with SIMD (System.Numerics) and making it faster than a for loop 显示 asm:vmulpd / vhaddpd ymm0, ymm0, ymm0 / vextractf128 xmm1, ymm0, 1 / vaddpd xmm0, xmm0, xmm1)。
  • 我不知道是否有办法说服 JIT 做同样的洗牌,但不与 System.Numerics 相乘(不带 Intrinsics .GetUpper() / Sse2.Add);我希望仅循环遍历元素会导致存储/重新加载可能会更糟,尤其是对于 256 位浮点向量(8 个元素而不是 4 个)。
  • c# multiplying array elements using system.numerics 表示仅使用 System.Numerics 是不可能的。 :/ (除非有对加减的特殊支持;那是要求用乘减来减少。)
  • 是的,JIT 在这里是有限的。当前的 JIT 至少会在 Vector&lt;T&gt;.Count 上自动展开循环,但它仍然会发出负载或 vextractf128/vpsrldq 对来读取上面的元素。不幸的是,做不必要的乘法仍然更便宜。
  • 是的,这样的问题就是 System.Runtime.Intrinsics 添加直接 ISA 映射的原因。在 .NET 5+ 中,存在从 System.Numerics.Vector&lt;T&gt;System.Runtime.Intrinsics.Vector256&lt;T&gt;(或 Vector128&lt;T&gt; 视情况而定)的无操作转换。这样,高效的版本就可以手动实现了。
猜你喜欢
  • 2017-03-02
  • 2021-02-20
  • 1970-01-01
  • 2019-09-19
  • 2012-11-07
  • 2015-09-20
  • 1970-01-01
  • 2021-08-12
  • 1970-01-01
相关资源
最近更新 更多