问题描述:对于Point[] points坐标数组(Point是坐标点,包含X与Y),请计算两两坐标点之间的距离。
思路:既然是算距离,没有别的要求,只需要最简单的曼哈顿距离就行。
测试数据:
- Random random = new Random();
- int n = 3000;
- Point[] points = new Point[n];
- for (int i = 0; i < n; i++)
- {
- points[i] = new Point(random.Next(10), random.Next(10));
- }
方法一:采用普通遍历法
- Stopwatch sw = Stopwatch.StartNew();
- int m = (n * n - n) / 2;
- List<int> list2 = new List<int>(m);
- for (int i = 0; i < n; i++)
- {
- Point p= points[i];
- for (int j = i + 1; j < n; j++)
- {
- Point p2 = points[j];
- int dif = Math.Abs(p.X - p2.X) + Math.Abs(p.Y - p2.Y);
- list2.Add(dif);
- }
- }
- sw.Stop();
- Console.WriteLine($"普通耗时:{sw.ElapsedMilliseconds}ms");
方法二:采用SIMD加速
- public static int[] CalculateDistance(Point[] points)
- {
- int n = points.Length;
- int m = (n * n - n) >> 1;
- int[] ints = new int[m];
- int k = 0;
- int vsize = Vector128<int>.Count;
- if (n <= vsize)// 如果数据量小于等于vsize采用指针处理
- {
- fixed (Point* ptr = points)
- {
- for (int i = 0; i < n; i++)
- {
- Point* p1 = ptr + i;
- for (int j = i + 1; j < n; j++)
- {
- Point* p2 = ptr + j;
- int dif = Math.Abs(p1->X - p2->X) + Math.Abs(p1->Y - p2->Y);
- ints[k++] = dif;
- }
- }
- return ints;
- }
- }
-
- int t = 0;
- int[] xs = new int[n];
- int[] ys = new int[n];
- fixed (Point* ptr = points)
- {
- fixed (int* xptr = xs, yptr = ys, rptr = ints)
- {
- // 分离x与y
- for (int i = 0; i < n; i++)
- {
- Point* p = ptr + i;
- *(xptr + i) = p->X;
- *(yptr + i) += p->Y;
- }
- // 开始向量计算
- for (int i = 0; i < n; i += vsize)
- {
- Vector128<int> vx1 = *(Vector128<int>*)(xptr + i);
- Vector128<int> vy1 = *(Vector128<int>*)(yptr + i);
- for (int j = i + 1; j < n; j++)
- {
- Vector128<int> vx2 = *(Vector128<int>*)(xptr + j);
- Vector128<int> vy2 = *(Vector128<int>*)(yptr + j);
- // 向量运算
- var vDifference = Sse2.Add(Vector128.Abs(Sse2.Subtract(vx1, vx2)), Vector128.Abs(Sse2.Subtract(vy1, vy2)));
- int* maskPtr = (int*)&vDifference;
- int h = n - j;
- for (int a = 0; a < vsize; a++)
- {
- if (a >= h) break;
- *(rptr + t++) = *(maskPtr + a);
- }
- }
- }
- }
- }
- return ints;
- }
注:根据CPU选择合适的Vector,比如Vector256、Vector512等等。本文只用Vector128.
测试结果(Release环境):
| 数据量 | 3000 | 5000 | 7000 | 10000 | 30000 |
| 普通耗时(ms) | 43 | 127 | 211 | 538 | 3872 |
| 向量耗时(ms) | 19 | 56 | 68 | 190 | 1092 |
结论:明显向量运算性能优于普通计算。