阵列加速

银色阴影

活跃的成员
已加入
2020年3月7日
留言内容
30
编程经验
10+
您好,我有一个程序很忙于访问数组,所以我一直在尝试优化速度。这对于整个程序要进行大量矩阵操作的高度迭代非常重要。我希望对下面的代码提出任何批评,或者希望进一步提出建议以进一步提高它的速度。

当前的运行时间(在释放模式下)分别以ms为单位,相对时间差相对恒定,此刻,选项4看起来可能是最好的,这表示速度比选项2显着提高,而选项2是当前的方法节目。在我更改整个数组之前,是否有任何明显的改进或更好的方法,或者下面的代码有任何问题,这些问题可能会带来奇怪的结果?

Ms1 128
Ms2 29
Ms3 228
Ms4 7

阵列访问速度福彩12选5走势图:
 [TestMethod]
        [MethodImpl(MethodImplOptions.NoInlining)]
        public unsafe void TestDoubleDoubleArrayWithPts()
        {

            double[,] Array = new double[10000,1000];
            var watch = Stopwatch.StartNew();
            int UpperBound0 = Array.GetUpperBound(0);
            int UpperBound1 = Array.GetUpperBound(1);

            watch.Restart();
            for (int i = 0; i < Array.GetUpperBound(0); i++)
                for (int y = 0; y < Array.GetUpperBound(1); y++)
                    Array[i,y] = 10D * 10D;

            var elapsedMs1 = watch.ElapsedMilliseconds;

            watch.Restart();
            for (int i = 0; i < UpperBound0; i++)
                for (int y = 0; y < UpperBound1; y++)
                    Array[i, y] = 10D * 10D;

            var elapsedMs2 = watch.ElapsedMilliseconds;

            watch.Restart();
            fixed (double* ptr = Array)
            {
                for (int i = 0; i < Array.GetUpperBound(0); i++)
                    for (int y = 0; y < Array.GetUpperBound(1); y++)
                        *(ptr + i * Array.GetUpperBound(1) + y) = 10D * 10D;    
            }

            var elapsedMs3 = watch.ElapsedMilliseconds;

            watch.Restart();
            fixed (double* ptr = Array)
            {
                for (int i = 0; i < UpperBound0; i++)
                    for (int y = 0; y < UpperBound1; y++)
                        *(ptr + i*UpperBound1 + y) = 10D * 10D;      
            }

            var elapsedMs4 = watch.ElapsedMilliseconds;

            System.Windows.Forms.MessageBox.Show(elapsedMs1.ToString() + " " + elapsedMs2.ToString() + " " + elapsedMs3.ToString() + " " + elapsedMs4.ToString());
       
        }
 
Solution
是的,您的权利,现在您提起它时看起来很奇怪,当我福彩12选5走势图它时,结果看起来还不错,这里晚了,所以明天要检查一下。如果结果实际上是正确的,也许可以简化程序,则最终矩阵应该围绕对角线对称,这在数学上可能有些奇怪。可能只是错了。实际上,应该能够将sqrt调用减少一半,因为它是对称的,但是我太讨厌让它今天工作了。需要重新思考。

parralell可能很有趣!

对于纯塔模拟,我无法减少对该函数的调用次数,但对于流和常规Flash计算,一定可以。

银色阴影

活跃的成员
已加入
2020年3月7日
留言内容
30
编程经验
10+
您仍然可以将Spans 3设为最快。我不明白,也许是不同的处理器? (AMD Ryzen 9 3900X)。无论如何,我同意数组版本更简单,更易于维护,并且易于将相同的方法应用于其他数组。添加一些指针使其可读性降低。

令人惊讶的是,相对较小的更改使程序在速度上变得相当不错。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
作为后续措施,我唯一可以得到的方法"back to arrays 3"运行最快的方法是运行Debug版本而不是Release版本。这在我的笔记本电脑(Ryzen 7),旧PC(AMD Phenom II)和工作笔记本电脑(iCore 7)之间是一致的。请始终使用发布版本进行计时。

我还在您的OP中看到您正在将这些作为单元福彩12选5走势图运行。不要这样做,因为VS福彩12选5走势图引擎会产生各种开销。希望您已经切换到使用独立控制台应用程序,就像我上面一样。

我真的应该开始使用 基准点网 以确保更好的性能福彩12选5走势图,因为它会分别编译一个Release版本,然后计时该版本。这是BenchmarkDotNet的其他优点。缺点是我不能再复制和粘贴代码供他人尝试,而不必让他们先安装BenchmarkDotNet Nuget软件包,而实际上基准福彩12选5走势图将花费更长的时间。也许我可以做到两全其美-使用快速的TimeIt()代码进行快速福彩12选5走势图,然后使用BenchmarkDotNet获得完整的基准福彩12选5走势图。
 

银色阴影

活跃的成员
已加入
2020年3月7日
留言内容
30
编程经验
10+
所有人都在realease模式下运行,我只是在控制台中尝试了您的原始代码,但仍然使Span 3的速度比Back To Arrays 3慢。无论如何,我认为也许我们已经对这一例程进行了尽可能的优化,例如再次访问该地区,再次感谢您的宝贵帮助!

2021-01-15.png
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,028
地点
挪威
编程经验
10+
奇怪,这些是我的结果 @跳伞 在AMD Ryzen 3600X上发布的版本16中的福彩12选5走势图代码:
C#:
Original pointers: Average: 503 ms
Back to arrays: Average: 592 ms
Back to arrays 2: Average: 424 ms
Back to arrays 3: Average: 325 ms
Spans: Average: 464 ms
Spans 2: Average: 300 ms
Spans 3: Average: 232 ms
 

银色阴影

活跃的成员
已加入
2020年3月7日
留言内容
30
编程经验
10+
奇怪,这些是我的结果 @跳伞 在AMD Ryzen 3600X上发布的版本16中的福彩12选5走势图代码:
C#:
Original pointers: Average: 503 ms
Back to arrays: Average: 592 ms
Back to arrays 2: Average: 424 ms
Back to arrays 3: Average: 325 ms
Spans: Average: 464 ms
Spans 2: Average: 300 ms
Spans 3: Average: 232 ms
我想我明白了,您在x64模式下运行?
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
是。如果要获得最佳性能,或要在64位计算机上运行64位操作系统,则应以64位进程运行。如果您以32位但32位进程运行,则64位操作系统必须为非子级32位进程的往返进程支付开销。
 

银色阴影

活跃的成员
已加入
2020年3月7日
留言内容
30
编程经验
10+
是。如果要获得最佳性能,或要在64位计算机上运行64位操作系统,则应以64位进程运行。如果您以32位但32位进程运行,则64位操作系统必须为非子级32位进程的往返进程支付开销。
是的,我没有特殊原因将其保留为Any Cpu。现在都更快了。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
多么有趣的结果...尝试仅处理矩阵的顶部对角线,然后尝试将其镜像到较低的对角线,似乎比仅顺序计算所有矩阵元素要慢。我从未期望过完成一半的工作实际上需要更长的时间。展示了如何使用CPU缓存而不是使用CPU缓存有所不同。

C#:
基准点网=v0.12.1, OS=Windows 10.0.19041.685 (2004/?/20H1)
AMD Ryzen 7 PRO 2700U w/ Radeon Vega Mobile Gfx, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.102
  [Host]     : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
  DefaultJob : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT


|                        Method |     Mean |    Error |   StdDev |   Median |
|------------------------------ |---------:|---------:|---------:|---------:|
| DoAllItemsDiagonalSpecialCase | 532.2 ms | 10.55 ms | 29.77 ms | 540.6 ms |
|           DoAllItemsSegmented | 462.0 ms |  9.22 ms | 13.80 ms | 464.9 ms |
|        DoAllItemsDiagonalLast | 499.7 ms |  9.93 ms | 15.47 ms | 498.9 ms |
|        MirrorItemsConditional | 745.8 ms | 14.39 ms | 21.55 ms | 744.3 ms |
|      MirrorItemsDiagonalFirst | 559.7 ms | 10.97 ms | 10.26 ms | 563.0 ms |
|       MirrorItemsDiagonalLast | 564.0 ms | 11.19 ms | 14.16 ms | 563.1 ms |
|                    DoJustHalf | 247.5 ms |  5.29 ms | 15.43 ms | 246.7 ms |
|  DoJustHalfThenMirrorByColumn | 742.9 ms | 14.71 ms | 17.52 ms | 741.0 ms |
|     DoJustHalfThenMirrorByRow | 778.9 ms | 12.73 ms | 27.66 ms | 773.8 ms |

那是对以下代码进行基准福彩12选5走势图:
C#:
using System;
using System.Linq;
using 基准点网.Attributes;
using 基准点网.Running;

namespace AMixBenchmark
{
    public static class ArrayMaker
    {
        static Random _random = new Random(123);

        public static double[] MakeRandomOneDimensionalArray(int n)
            => Enumerable.Range(0, n)
                         .Select(i => _random.NextDouble())
                         .ToArray();

        public static double[,] MakeRandomTwoDimensionalArray(int n)
        {
            var arr = new double[n, n];
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                    arr[i, j] = _random.NextDouble();
            return arr;
        }
    }

    public class BenchArray
    {
        int n = 10000;
        double[] ai;
        double[,] kijm;
        double[,] Aij;

        public BenchArray()
        {
            ai = ArrayMaker.MakeRandomOneDimensionalArray(n);
            kijm = ArrayMaker.MakeRandomTwoDimensionalArray(n);
            Aij = new double[n, n];
        }

        [Benchmark]
        public void DoAllItemsDiagonalSpecialCase()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                for (int j = 0; j < n; j++)
                {
                    if (i == j)
                        Aij[i, j] = aii;
                    else
                        Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                }
            }
        }

        [Benchmark]
        public void DoAllItemsSegmented()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                for (int j = 0; j < i; j++)
                    Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);

                Aij[i, i] = aii;

                for (int j = i + 1; j < n; j++)
                    Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
            }
        }

        [Benchmark]
        public void DoAllItemsDiagonalLast()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                for (int j = 0; j < n; j++)
                    Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);

                Aij[i, i] = aii;
            }
        }

        [Benchmark]
        public void MirrorItemsConditional()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                for (int j = 0; j < n; j++)
                {
                    if (i > j)
                        Aij[j, i] = Aij[i, j];
                    else
                        Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                }
                Aij[i, i] = aii;
            }
        }

        [Benchmark]
        public void MirrorItemsDiagonalFirst()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                Aij[i, i] = aii;
                for (int j = i + 1; j < n; j++)
                {
                    var value = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                    Aij[i, j] = value;
                    Aij[j, i] = value;
                }
            }
        }

        [Benchmark]
        public void MirrorItemsDiagonalLast()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                for (int j = i + 1; j < n; j++)
                {
                    var value = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                    Aij[i, j] = value;
                    Aij[j, i] = value;
                }
                Aij[i, i] = aii;
            }
        }

        [Benchmark]
        public void DoJustHalf()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                Aij[i, i] = aii;
                for (int j = i + 1; j < n; j++)
                    Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
            }
        }

        [Benchmark]
        public void DoJustHalfThenMirrorByColumn()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                Aij[i, i] = aii;
                for (int j = i + 1; j < n; j++)
                    Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
            }

            for (int i = 0; i < n; i++)
            {
                for (int j = i + 1; j < n; j++)
                    Aij[j, i] = Aij[i, j];
            }
        }

        [Benchmark]
        public void DoJustHalfThenMirrorByRow()
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                Aij[i, i] = aii;
                for (int j = i + 1; j < n; j++)
                    Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
            }

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < i; j++)
                    Aij[i, j] = Aij[j, i];
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var 概要 = BenchmarkRunner.Run<BenchArray>();
        }
    }
}
 

银色阴影

活跃的成员
已加入
2020年3月7日
留言内容
30
编程经验
10+
因此,现在我正在运行x64(释放模式),我发现数组的大小会影响相对速度。对于大型数组(10000 x 10000),修改后的Back to Arrays 3方法最快,而Span 3紧随其后。

但是,在我的特殊情况下,阵列的大小会相对较小(但要成千上万次),阵列的大小取决于塔中塔盘的数量,其中约50个是中位数(最高的塔可能有100个塔托盘,除此之外,它们还可以分为两个物理塔,但并不常见。

如果我以50的数组大小运行福彩12选5走势图,我会发现"Back to Arrays 3" & "Modifed 回到数组3 (or 3a)"在性能上和速度上都相等。

这暗示着针对此特定问题的最佳解决方案是使用“简单” C#代码(感谢Skydiver!)优化数组处理,而无需使用span或指针!还有其他数组,我可以尝试对代码进行相同的重新排列。

该程序现在可以在大约3.9秒内解决8个蒸馏塔和一个简单的流程图,这就是PDG!

现在,我可以继续将其他地方的基本Flash计算重写为“由内而外”(因此对复杂的热力学例程的调用更少)。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,500
地点
弗吉尼亚州切萨皮克
编程经验
10+
我很高兴为您做好一切。

由于BenchmarkDotNet是我的闪亮新玩具,因此运行数组大小为50x50和100x100的结果如下:
C#:
基准点网=v0.12.1, OS=Windows 10.0.19041.746 (2004/?/20H1)
AMD Ryzen 7 PRO 2700U w/ Radeon Vega Mobile Gfx, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.102
  [Host]     : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
  DefaultJob : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT


|                     Method |  _n |      Mean |     Error |    StdDev |    Median | Ratio | RatioSD |
|--------------------------- |---- |----------:|----------:|----------:|----------:|------:|--------:|
|                   CalcAMix |  50 | 10.873 us | 0.2089 us | 0.1851 us | 10.782 us |  0.82 |    0.01 |
|             CalcAMixArrays |  50 | 13.279 us | 0.0926 us | 0.0723 us | 13.258 us |  1.00 |    0.00 |
|            CalcAMixArrays2 |  50 |  9.492 us | 0.2571 us | 0.7377 us |  9.857 us |  0.70 |    0.05 |
|            CalcAMixArrays3 |  50 |  9.632 us | 0.1921 us | 0.4010 us |  9.436 us |  0.73 |    0.04 |
|              CalcAMixSpans |  50 | 10.204 us | 0.7878 us | 2.1298 us |  9.487 us |  0.81 |    0.20 |
|             CalcAMixSpans2 |  50 |  7.291 us | 0.0284 us | 0.0237 us |  7.296 us |  0.55 |    0.00 |
|             CalcAMixSpans3 |  50 |  5.719 us | 0.1088 us | 0.1252 us |  5.729 us |  0.43 |    0.01 |
|     CalcAMixMirroredArrays |  50 | 12.492 us | 0.2496 us | 0.3959 us | 12.351 us |  0.94 |    0.03 |
|    CalcAMixMirroredArrays2 |  50 |  7.602 us | 0.1500 us | 0.3566 us |  7.728 us |  0.57 |    0.03 |
|    CalcAMixMirroredArrays3 |  50 |  6.095 us | 0.0261 us | 0.0204 us |  6.096 us |  0.46 |    0.00 |
|      CalcAMixMirroredSpans |  50 | 12.993 us | 0.2596 us | 0.4042 us | 13.012 us |  0.97 |    0.03 |
|     CalcAMixMirroredSpans2 |  50 |  7.999 us | 0.2216 us | 0.6065 us |  7.917 us |  0.59 |    0.05 |
|     CalcAMixMirroredSpans3 |  50 |  6.611 us | 0.1343 us | 0.3810 us |  6.682 us |  0.49 |    0.03 |
|    CalcAMixMirroredSpans3a |  50 |  4.233 us | 0.1086 us | 0.3045 us |  4.218 us |  0.30 |    0.01 |
| CalcAMixMirroredPointers3a |  50 |  4.236 us | 0.0846 us | 0.2316 us |  4.173 us |  0.33 |    0.02 |
|                            |     |           |           |           |           |       |         |
|                   CalcAMix | 100 | 48.963 us | 0.9767 us | 1.8345 us | 48.129 us |  0.90 |    0.04 |
|             CalcAMixArrays | 100 | 54.326 us | 1.0678 us | 1.5651 us | 53.187 us |  1.00 |    0.00 |
|            CalcAMixArrays2 | 100 | 35.488 us | 0.7020 us | 1.5112 us | 35.841 us |  0.65 |    0.03 |
|            CalcAMixArrays3 | 100 | 38.967 us | 0.7766 us | 0.8309 us | 38.692 us |  0.72 |    0.02 |
|              CalcAMixSpans | 100 | 35.771 us | 0.7118 us | 1.8999 us | 36.377 us |  0.66 |    0.04 |
|             CalcAMixSpans2 | 100 | 30.509 us | 0.6017 us | 0.9188 us | 29.996 us |  0.56 |    0.02 |
|             CalcAMixSpans3 | 100 | 22.988 us | 0.4522 us | 0.7173 us | 22.457 us |  0.42 |    0.02 |
|     CalcAMixMirroredArrays | 100 | 51.271 us | 1.0005 us | 1.6989 us | 50.254 us |  0.95 |    0.04 |
|    CalcAMixMirroredArrays2 | 100 | 30.479 us | 0.8260 us | 2.1759 us | 30.657 us |  0.55 |    0.03 |
|    CalcAMixMirroredArrays3 | 100 | 26.234 us | 0.5192 us | 0.8530 us | 26.558 us |  0.48 |    0.02 |
|      CalcAMixMirroredSpans | 100 | 52.468 us | 1.0319 us | 1.1469 us | 51.733 us |  0.97 |    0.04 |
|     CalcAMixMirroredSpans2 | 100 | 30.133 us | 0.6320 us | 1.8335 us | 29.517 us |  0.55 |    0.04 |
|     CalcAMixMirroredSpans3 | 100 | 25.254 us | 0.5472 us | 1.6048 us | 24.164 us |  0.47 |    0.04 |
|    CalcAMixMirroredSpans3a | 100 | 15.743 us | 0.3161 us | 0.9120 us | 15.135 us |  0.29 |    0.02 |
| CalcAMixMirroredPointers3a | 100 | 15.988 us | 0.3186 us | 0.7754 us | 15.551 us |  0.30 |    0.02 |

有趣的结果是,对矩阵的一半进行镜像似乎确实具有一些好处,这与我在29号帖子中得出的结果不同。我认为使用较小的矩阵,整个矩阵都适合CPU缓存,因此完成一半的工作实际上是有回报的,这与我仅对填充和镜像进行基准福彩12选5走势图时的10000x10000巨大矩阵不同。

C#:
using System;
using System.Linq;
using 基准点网.Attributes;
using 基准点网.Running;

namespace AMixBenchmark
{
    public static class ArrayMaker
    {
        static Random _random = new Random(123);

        public static double[] MakeRandomOneDimensionalArray(int n)
            => Enumerable.Range(0, n)
                         .Select(i => _random.NextDouble())
                         .ToArray();

        public static double[,] MakeRandomTwoDimensionalArray(int n)
        {
            var arr = new double[n, n];
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                    arr[i, j] = _random.NextDouble();
            return arr;
        }
    }

    public class Bench
    {
        [Params(50, 100)]
        public int _n;
        double [] _xy;
        double [] _ai;
        double [,] _kijm;
        double [,] _aij;
        double [] _sumai;

        [GlobalSetup]
        public void Setup()
        {
            _xy = ArrayMaker.MakeRandomOneDimensionalArray(_n);
            _ai = ArrayMaker.MakeRandomOneDimensionalArray(_n);
            _kijm = ArrayMaker.MakeRandomTwoDimensionalArray(_n);
            _aij = new double[_n, _n];
            _sumai = new double[_n];
        }

        [Benchmark] public double CalcAMix() => CalcAmixInner(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixArrays() => CalcAmixArraysInner(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixArrays2() => CalcAmixArraysInner2(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixArrays3() => CalcAmixArraysInner3(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixSpans() => CalcAmixSpansInner(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixSpans2() => CalcAmixSpansInner2(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixSpans3() => CalcAmixSpansInner3(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixMirroredArrays() => CalcAmixMirroredArraysInner(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixMirroredArrays2() => CalcAmixMirroredArraysInner2(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixMirroredArrays3() => CalcAmixMirroredArraysInner3(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixMirroredSpans() => CalcAmixMirroredSpansInner(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixMirroredSpans2() => CalcAmixMirroredSpansInner2(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixMirroredSpans3() => CalcAmixMirroredSpansInner3(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixMirroredSpans3a() => CalcAmixMirroredSpansInner3a(_n, _xy, _ai, _kijm, _aij, _sumai);
        [Benchmark] public double CalcAMixMirroredPointers3a() => CalcAmixMirroredPointersInner3a(_n, _xy, _ai, _kijm, _aij, _sumai);

        static public unsafe double CalcAmixInner(int n, double[] XY, double[] ai, double[,] kijm, double[,] Aij, double[] sumAi)
        {
            double amix = 0;
            int UpperBound0 = Aij.GetUpperBound(0);
            int UpperBound1 = Aij.GetUpperBound(1);

            fixed (double* ptr = Aij, aiPtr = ai, kijmPtr = kijm)
            {
                double* element = ptr;
                double* kijelement = kijmPtr;
                double* aielement = aiPtr;
                for (int i = 0; i <= UpperBound0; i++)
                {
                    for (int j = 0; j <= UpperBound1; j++)
                    {
                        if (i == j)
                            *element = *aielement;
                        else
                            *element = Math.Sqrt(*(aiPtr + i) * *(aiPtr + j)) * (1 - *kijelement);

                        element++;
                        kijelement++;
                    }

                    aielement++;
                }
            }

            fixed (double* ptrAij = Aij, ptrXY = XY, ptrsumAI = sumAi)
            {
                double* elementAij = ptrAij;
                double* elementsumAI = ptrsumAI;
                double* elementXy = ptrXY;

                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        *elementsumAI += *elementXy * *elementAij;
                        elementXy++;
                        elementAij++;
                    }

                    amix += *elementsumAI * *(ptrXY + i);
                    elementXy = ptrXY;
                    elementsumAI++;
                }
            }
            return amix;
        }

        static public double CalcAmixArraysInner(int n, double[] XY, double[] ai, double[,] kijm, double[,] Aij, double[] sumAi)
        {
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (i == j)
                        Aij[i, j] = ai[i];
                    else
                        Aij[i, j] = Math.Sqrt(ai[i] * ai[j]) * (1 - kijm[i, j]);
                }
            }

            double amix = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                    sumAi[i] += XY[j] * Aij[i, j];

                amix += sumAi[i] * XY[i];
            }
            return amix;
        }

        static public double CalcAmixArraysInner2(int n, double[] XY, double[] ai, double[,] kijm, double[,] Aij, double[] sumAi)
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                for (int j = 0; j < n; j++)
                    Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);

                Aij[i, i] = aii;
            }

            double amix = 0;
            for (int i = 0; i < n; i++)
            {
                double sum = 0;
                for (int j = 0; j < n; j++)
                    sum += XY[j] * Aij[i, j];

                sumAi[i] = sum;
                amix += sum * XY[i];
            }
            return amix;
        }

        static public double CalcAmixArraysInner3(int n, double[] XY, double[] ai, double[,] kijm, double[,] Aij, double[] sumAi)
        {
            double amix = 0;

            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                double sum = XY[i] * aii;

                for (int j = 0; j < n; j++)
                {
                    var value = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                    Aij[i, j] = value;
                    sum += XY[j] * value;
                }

                sum -= XY[i] * Aij[i, i];
                Aij[i, i] = aii;

                sumAi[i] = sum;
                amix += sum * XY[i];
            }

            return amix;
        }

        static public double CalcAmixSpansInner(int n,
                                                ReadOnlySpan<double> XY,
                                                ReadOnlySpan<double> ai,
                                                double[,] kijm,
                                                double[,] Aij,
                                                Span<double> sumAi)
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                for (int j = 0; j < n; j++)
                    Aij[i, j] = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);

                Aij[i, i] = aii;
            }

            double amix = 0;
            for (int i = 0; i < n; i++)
            {
                double sum = 0;
                for (int j = 0; j < n; j++)
                    sum += XY[j] * Aij[i, j];

                sumAi[i] = sum;
                amix += sum * XY[i];
            }
            return amix;
        }

        static public unsafe double CalcAmixSpansInner2(int n,
                                                 ReadOnlySpan<double> XY,
                                                 ReadOnlySpan<double> ai,
                                                 double[,] kijm,
                                                 double[,] Aij,
                                                 Span<double> sumAi)
        {
            fixed (double* kijmPtr = kijm, AijPtr = Aij)
            {
                var kijmSpan = new ReadOnlySpan<double>(kijmPtr, kijm.Length);
                var kijmRowISpan = kijmSpan.Slice(0);
                var AijSpan = new Span<double>(AijPtr, Aij.Length);
                var AijRowISpan = AijSpan.Slice(0);

                for (int i = 0; i < n; i++)
                {
                    var aii = ai[i];
                    for (int j = 0; j < n; j++)
                        AijRowISpan[j] = Math.Sqrt(aii * ai[j]) * (1 - kijmRowISpan[j]);

                    AijRowISpan[i] = aii;
                    kijmRowISpan = kijmRowISpan.Slice(n);
                    AijRowISpan = AijRowISpan.Slice(n);
                }

                double amix = 0;
                AijRowISpan = AijSpan.Slice(0);
                for (int i = 0; i < n; i++)
                {
                    double sum = 0;
                    for (int j = 0; j < n; j++)
                        sum += XY[j] * AijRowISpan[j];

                    sumAi[i] = sum;
                    amix += sum * XY[i];
                    AijRowISpan = AijRowISpan.Slice(n);
                }
                return amix;
            }
        }

        static public unsafe double CalcAmixSpansInner3(int n,
                                                        ReadOnlySpan<double> XY,
                                                        ReadOnlySpan<double> ai,
                                                        double[,] kijm,
                                                        double[,] Aij,
                                                        Span<double> sumAi)
        {
            fixed (double* kijmPtr = kijm, AijPtr = Aij)
            {
                var kijmSpan = new ReadOnlySpan<double>(kijmPtr, kijm.Length);
                var kijmRowISpan = kijmSpan.Slice(0);
                var AijSpan = new Span<double>(AijPtr, Aij.Length);
                var AijRowISpan = AijSpan.Slice(0);
                double amix = 0;

                for (int i = 0; i < n; i++)
                {
                    var aii = ai[i];
                    double sum = XY[i] * aii;

                    for (int j = 0; j < n; j++)
                    {
                        var value = Math.Sqrt(aii * ai[j]) * (1 - kijmRowISpan[j]);
                        AijRowISpan[j] = value;
                        sum += XY[j] * value;
                    }

                    sum -= XY[i] * AijRowISpan[i];
                    AijRowISpan[i] = aii;

                    sumAi[i] = sum;
                    amix += sum * XY[i];

                    kijmRowISpan = kijmRowISpan.Slice(n);
                    AijRowISpan = AijRowISpan.Slice(n);
                }

                return amix;
            }
        }

        static public double CalcAmixMirroredArraysInner(int n, double[] XY, double[] ai, double[,] kijm, double[,] Aij, double[] sumAi)
        {
            for (int i = 0; i < n; i++)
            {
                Aij[i, i] = ai[i];
                for (int j = i + 1; j < n; j++)
                {
                    Aij[i, j] = Math.Sqrt(ai[i] * ai[j]) * (1 - kijm[i, j]);
                    Aij[j, i] = Aij[i, j];
                }
            }

            double amix = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                    sumAi[i] += XY[j] * Aij[i, j];

                amix += sumAi[i] * XY[i];
            }
            return amix;
        }

        static public double CalcAmixMirroredArraysInner2(int n, double[] XY, double[] ai, double[,] kijm, double[,] Aij, double[] sumAi)
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                Aij[i, i] = aii;
                for (int j = i + 1; j < n; j++)
                {
                    var value = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                    Aij[i, j] = value;
                    Aij[j, i] = value;
                }
            }

            double amix = 0;
            for (int i = 0; i < n; i++)
            {
                double sum = 0;
                for (int j = 0; j < n; j++)
                    sum += XY[j] * Aij[i, j];

                sumAi[i] = sum;
                amix += sum * XY[i];
            }
            return amix;
        }

        static public double CalcAmixMirroredArraysInner3(int n, double[] XY, double[] ai, double[,] kijm, double[,] Aij, double[] sumAi)
        {
            double amix = 0;

            for (int i = 0; i < n; i++)
            {
                double sum = 0;

                for (int j = 0; j < i; j++)
                    sum += XY[j] * Aij[i, j];

                var aii = ai[i];
                Aij[i, i] = aii;
                sum += XY[i] * aii;

                for (int j = i + 1; j < n; j++)
                {
                    var value = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                    Aij[i, j] = value;
                    Aij[j, i] = value;
                    sum += XY[j] * value;
                }

                sumAi[i] = sum;
                amix += sum * XY[i];
            }

            return amix;
        }

        static public double CalcAmixMirroredSpansInner(int n,
                                                        ReadOnlySpan<double> XY,
                                                        ReadOnlySpan<double> ai,
                                                        double[,] kijm,
                                                        double[,] Aij,
                                                        Span<double> sumAi)
        {
            for (int i = 0; i < n; i++)
            {
                Aij[i, i] = ai[i];
                for (int j = i + 1; j < n; j++)
                {
                    Aij[i, j] = Math.Sqrt(ai[i] * ai[j]) * (1 - kijm[i, j]);
                    Aij[j, i] = Aij[i, j];
                }
            }

            double amix = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                    sumAi[i] += XY[j] * Aij[i, j];

                amix += sumAi[i] * XY[i];
            }
            return amix;
        }

        static public double CalcAmixMirroredSpansInner2(int n,
                                                         ReadOnlySpan<double> XY,
                                                         ReadOnlySpan<double> ai,
                                                         double[,] kijm,
                                                         double[,] Aij,
                                                         Span<double> sumAi)
        {
            for (int i = 0; i < n; i++)
            {
                var aii = ai[i];
                Aij[i, i] = aii;
                for (int j = i + 1; j < n; j++)
                {
                    var value = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                    Aij[i, j] = value;
                    Aij[j, i] = value;
                }
            }

            double amix = 0;
            for (int i = 0; i < n; i++)
            {
                double sum = 0;
                for (int j = 0; j < n; j++)
                    sum += XY[j] * Aij[i, j];

                sumAi[i] = sum;
                amix += sum * XY[i];
            }
            return amix;
        }

        static public double CalcAmixMirroredSpansInner3(int n,
                                                         ReadOnlySpan<double> XY,
                                                         ReadOnlySpan<double> ai,
                                                         double[,] kijm,
                                                         double[,] Aij,
                                                         Span<double> sumAi)
        {
            double amix = 0;

            for (int i = 0; i < n; i++)
            {
                double sum = 0;

                for (int j = 0; j < i; j++)
                    sum += XY[j] * Aij[i, j];

                var aii = ai[i];
                Aij[i, i] = aii;
                sum += XY[i] * aii;

                for (int j = i + 1; j < n; j++)
                {
                    var value = Math.Sqrt(aii * ai[j]) * (1 - kijm[i, j]);
                    Aij[i, j] = value;
                    Aij[j, i] = value;
                    sum += XY[j] * value;
                }

                sumAi[i] = sum;
                amix += sum * XY[i];
            }

            return amix;
        }

        static public unsafe double CalcAmixMirroredSpansInner3a(int n,
                                                                 ReadOnlySpan<double> XY,
                                                                 ReadOnlySpan<double> ai,
                                                                 double[,] kijm,
                                                                 double[,] Aij,
                                                                 Span<double> sumAi)
        {
            fixed (double* kijmPtr = kijm, AijPtr = Aij)
            {
                var kijmSpan = new ReadOnlySpan<double>(kijmPtr, kijm.Length);
                var kijmRowISpan = kijmSpan.Slice(0);
                var AijSpan = new Span<double>(AijPtr, Aij.Length);
                var AijRowISpan = AijSpan.Slice(0);
                double amix = 0;

                for (int i = 0; i < n; i++)
                {
                    double sum = 0;

                    for (int j = 0; j < i; j++)
                        sum += XY[j] * AijRowISpan[j];

                    var aii = ai[i];
                    AijRowISpan[i] = aii;
                    sum += XY[i] * aii;

                    if (i + 1 < n)
                    {
                        var AijColJSpan = AijSpan.Slice((i + 1) * n);
                        for (int j = i + 1; j < n; j++)
                        {
                            var value = Math.Sqrt(aii * ai[j]) * (1 - kijmRowISpan[j]);
                            AijRowISpan[j] = value;
                            AijColJSpan[i] = value;
                            sum += XY[j] * value;

                            AijColJSpan = AijColJSpan.Slice(n);
                        }
                    }

                    sumAi[i] = sum;
                    amix += sum * XY[i];

                    kijmRowISpan = kijmRowISpan.Slice(n);
                    AijRowISpan = AijRowISpan.Slice(n);
                }

                return amix;
            }
        }

        static public unsafe double CalcAmixMirroredPointersInner3a(int n, double[] XY, double[] ai, double[,] kijm, double[,] Aij, double[] sumAi)
        {
            fixed (double* XYPtr = XY, aiPtr = ai, kijmPtr = kijm, AijPtr = Aij, sumAiPtr = sumAi)
            {
                var kijmRowI = kijmPtr;
                var AijDst = AijPtr;
                var sumAiDst = sumAiPtr;
                double amix = 0;

                for (int i = 0; i < n; i++)
                {
                    var XYSrc = XYPtr;
                    double sum = 0;

                    for (int j = 0; j < i; j++)
                        sum += *XYSrc++ * *AijDst++;

                    var aii = aiPtr[i];
                    *AijDst++ = aii;
                    sum += *XYSrc++ * aii;

                    var AijColJSpan = &AijPtr[(i + 1) * n + i];
                    var kijmSrc = &kijmRowI[i + 1];
                    for (int j = i + 1; j < n; j++)
                    {
                        var value = Math.Sqrt(aii * aiPtr[j]) * (1 - *kijmSrc++);
                        *AijDst++ = value;
                        *AijColJSpan = value;
                        sum += *XYSrc++ * value;

                        AijColJSpan += n;
                    }

                    *sumAiDst++ = sum;
                    amix += sum * XYPtr[i];

                    kijmRowI += n;
                }

                return amix;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var 概要 = BenchmarkRunner.Run<Bench>();
        }
    }
}
 
最佳 底部