首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SIMD向量-复数?

SIMD向量-复数?
EN

Stack Overflow用户
提问于 2018-12-08 06:51:09
回答 1查看 574关注 0票数 1

我想在.NET核心中使用System.Numerics.Vector命名空间,但我遇到了不支持复数向量的问题。目前,Vector类型适用于任何原始类型,从字节到双精度。我不是程序员,所以我可能对一些低级/概念性的东西一无所知,但是为什么不支持复数呢?据我所知,唯一的问题可能是复杂类型是一个托管结构。我能不能只扩展Register类型来包含[FieldOffset(0)] internal Complex complex_0并围绕它构建新的函数?

我愿意自己做类型扩展,但我想问一下,是否有什么原因没有把它包括在第一位,因为似乎很多信号处理工作都会从复向量和SIMD中受益良多。

EN

回答 1

Stack Overflow用户

发布于 2020-06-29 14:57:14

System.Numerics.Vector对您的目标毫无用处。您可以依赖System.Runtime.Intrinsics名称空间中的Vector256类。必要的说明在System.Runtime.Intrinsics.X86.Avx类中公开。(Vector128在这里没有什么帮助,因为它表示一个复数。我没有找到任何可以帮助我在不复制的情况下将复杂类重新解释为Vector128的魔术,否则我们将能够增强为复杂类提供的内置操作符。)

所以,我们的想法是

将复杂数据以跨度表示,并在这些跨度上实现算术运算符将这些跨度转换为Vector256

  • 并使用Avx

参见下面的示例代码:

代码语言:javascript
复制
public static class ComplexAvx
    {
        public static Span<Complex> Add(ReadOnlySpan<Complex> left, ReadOnlySpan<Complex> right)
        {
            var result = new Complex[Math.Min(left.Length, right.Length)].AsSpan();
            var vectorRes = MemoryMarshal.Cast<Complex, Vector256<double>>(result);
            var vectorLeft = MemoryMarshal.Cast<Complex, Vector256<double>>(left);
            var vectorRight = MemoryMarshal.Cast<Complex, Vector256<double>>(right);
            for (int i = 0; i < vectorRes.Length; i++)
                vectorRes[i] = Avx.Add(vectorLeft[i], vectorRight[i]);

            for (int i = 2 * vectorRes.Length; i < result.Length; i++)
                result[i] = left[i] + right[i];
            return result;
        }

        public static Span<Complex> Subtract(ReadOnlySpan<Complex> left, ReadOnlySpan<Complex> right)
        {
            var result = new Complex[Math.Min(left.Length, right.Length)].AsSpan();
            var vectorRes = MemoryMarshal.Cast<Complex, Vector256<double>>(result);
            var vectorLeft = MemoryMarshal.Cast<Complex, Vector256<double>>(left);
            var vectorRight = MemoryMarshal.Cast<Complex, Vector256<double>>(right);
            for (int i = 0; i < vectorRes.Length; i++)
                vectorRes[i] = Avx.Subtract(vectorLeft[i], vectorRight[i]);

            for (int i = 2 * vectorRes.Length; i < result.Length; i++)
                result[i] = left[i] - right[i];
            return result;
        }

        public static Span<Complex> Multiply(ReadOnlySpan<Complex> left, ReadOnlySpan<Complex> right)
        {
            var result = new Complex[Math.Min(left.Length, right.Length)].AsSpan();
            var vectorRes = MemoryMarshal.Cast<Complex, Vector256<double>>(result);
            var vectorLeft = MemoryMarshal.Cast<Complex, Vector256<double>>(left);
            var vectorRight = MemoryMarshal.Cast<Complex, Vector256<double>>(right);
            for (int i = 0; i < vectorRes.Length; i++)
            {
                var l = vectorLeft[i];  
                var r = vectorRight[i]; 
                vectorRes[i] = Avx.HorizontalAdd(
                    Avx.Multiply(
                        Avx.Multiply(l, r), 
                        Vector256.Create(1.0, -1.0, 1.0, -1.0)), 
                    Avx.Multiply(
                        l, 
                        Avx.Permute(r, 0b0101)
                        )); 
            }
            for (int i = 2 * vectorRes.Length; i < result.Length; i++)
                result[i] = left[i] * right[i];
            return result;
        }

    }

这段代码执行5次AVX操作来将两个复数相乘,而使用System.Numerics.Complex.Multiply将消耗8次乘法和4次加法。(当然,代码应该检查Avx.IsEnabled -为了简单起见,跳过了这一点)我没有为基准测试而烦恼,所以不确定它会在现代CPU上产生多少(如果有的话)收益。Avx512将允许使用相同的5条指令同时处理4条复杂指令;但这还有待于CLR的支持。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53677757

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档