是否可以基于 Vector<double> 在 .Net 中创建高效的 SIMD 双精度 Vector3

Posted

技术标签:

【中文标题】是否可以基于 Vector<double> 在 .Net 中创建高效的 SIMD 双精度 Vector3【英文标题】:Is it possible to create an efficient SIMD double precision Vector3 in .Net based on Vector<double> 【发布时间】:2017-07-10 10:08:25 【问题描述】:

当我问我的机器时

System.Numerics.Vector<double>.Count

答案是4,所以至少在我的机器上,SIMD 寄存器中有足够的位来保存 4 个双精度数字。

我已经尝试创建一个基于 System.Numerics.Vector&lt;double&gt; 的 Vector3 double,但我认为不可能创建一个与 System.Numerics.Vector3 具有相同形状的模型,它的性能比没有 SIMD 支持的基本 C# 代码更好。

例如我的尝试如下。我知道这是糟糕的代码。我只是想探索一下我可以用Vector&lt;double&gt; 做什么。

System.Numerics.Vector&lt;double&gt; 没有采用 N 个参数的构造函数。我明白为什么。这是因为在编译时你不知道Vector&lt;double&gt; 中可以容纳多少双打,所以库作者保护我不要在脚下开枪。

但是,如果我愿意冒险进行一些脚射,我可以改进以下代码吗?

using System.Numerics;

public struct Vector3Double


    public readonly double X;
    public readonly double Y;
    public readonly double Z;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public Vector3Double(double x, double y, double z) : this()
    
        X = x;
        Y = y;
        Z = z;
    

    // Factory for SIMD Vector<double> but it is slow because
    // I need to create an array on the heap to initialize
    static Vector<double> vd(double x, double y, double z) 
        => new Vector<double>(new []x,y,z,0);


    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static double Dot(Vector3Double a, Vector3Double b)
    
        var s = vd( a.X, a.Y, a.Z ) * vd( b.X, b.Y, b.Z );
        return s[0] + s[1] + s[2];
    

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Vector3Double Add(Vector3Double a, Vector3Double b)
    
        var s = vd( a.X, a.Y, a.Z ) + vd( b.X, b.Y, b.Z );
        return new Vector3Double( s[0], s[1], s[2] );
    

【问题讨论】:

这还能用吗? +* 似乎都返回了一个只有两个项目的 Vector&lt;double&gt;。所以尝试访问s[2] 会抛出IndexOutOfRangeException 这取决于你的机器。它是特定于硬件的。在我的机器上Vector&lt;double&gt;.Count 返回 4。在你的机器上它可能只返回 2。 我已经读过这个问题几次,但我仍然不完全清楚你在问什么。为什么不能只使用Vector3?您不能真正用 C# 编写自己的 SIMD 优化代码。您对发布的代码有什么具体问题?你只是想要它reviewed? Vector3 是单精度。我想要双精度。我想知道我是否可以使用 Vector ,其中 T 是双倍的。我发布的代码只是一个例子。它可以工作,但没有意义,因为它比简单的实现要慢。 无论如何,您都不应该将 linalg 向量放入 SIMD 向量中,否则在实现点积、长度和规范化时会遇到麻烦。 99% 的情况下,您应该做的是将所有 X 放入一个向量中,将所有 Y 放入另一个向量中,依此类推。 【参考方案1】:

如果您认为 Vector3d 的 size=16,则有一种方法可以做到这一点,就像您有第四个坐标一样。然后您可以使用 Unsafe.Read>(&v3d) 将 Vector3d 不安全地转换为 Vector。请注意,这仅在 Vector.Count 为 4 时才有效! 在 Vector 上执行 simd 操作后,您可以再次使用 Unsafe.Read(&result) 将结果转换回 Vector3d。

【讨论】:

以上是关于是否可以基于 Vector<double> 在 .Net 中创建高效的 SIMD 双精度 Vector3的主要内容,如果未能解决你的问题,请参考以下文章

求问 基于 vector 的矩阵乘法 怎么做的啊,没明白

C++ Vector 类作为其他类的成员

是否可以多线程同时执行非 void 函数? (C++)

是否可以用整数数组初始化双精度矢量?

用 boost.python 暴露 std::vector<double>

hdu4305生成树计数