In this post I will compare two methods that perform matrix multiplication. We start by defining the Matrix class:

class Matrix { private readonly double[,] _matrix; public Matrix(int dim1, int dim2) { _matrix = new double[dim1, dim2]; } public int Height { get { return _matrix.GetLength(0); } } public int Width { get { return _matrix.GetLength(1); } } public double this[int x, int y] { get { return _matrix[x, y]; } set { _matrix[x, y] = value; } } }

Next we add the first algorithm to the Matrix class which performs a naive multiplication:

public static Matrix NaiveMultiplication(Matrix m1, Matrix m2) { Matrix resultMatrix = new Matrix(m1.Height, m2.Width); for (int i = 0; i < resultMatrix.Height; i++) { for (int j = 0; j < resultMatrix.Width; j++) { resultMatrix[i, j] = 0; for (int k = 0; k < m1.Width; k++) { resultMatrix[i, j] += m1[i, k] * m2[k, j]; } } } return resultMatrix; }

The second method uses unsafe code:

public unsafe static Matrix UnsafeMultiplication(Matrix m1, Matrix m2) { int h = m1.Height; int w = m2.Width; int l = m1.Width; Matrix resultMatrix = new Matrix(h, w); unsafe { fixed (double* pm = resultMatrix._matrix, pm1 = m1._matrix, pm2 = m2._matrix) { int i1, i2; for (int i = 0; i < h; i++) { i1 = i * l; for (int j = 0; j < w; j++) { i2 = j; double res = 0; for (int k = 0; k < l; k++, i2 += w) { res += pm1[i1 + k] * pm2[i2]; } pm[i * w + j] = res; } } } } return resultMatrix; }

Now it’s time to measure the performance:

class Program { [DllImport("kernel32.dll")] static extern void QueryPerformanceCounter(ref long ticks); static long Measure(Action action, int count) { long startTicks = 0; QueryPerformanceCounter(ref startTicks); for (int i = 0; i < count; i++) { action(); } long endTicks = 0; QueryPerformanceCounter(ref endTicks); return endTicks - startTicks; } static void Main(string[] args) { Random random = new Random(); Matrix m1 = new Matrix(20, 30); for (int i = 0; i < m1.Height; i++) { for (int j = 0; j < m1.Width; j++) { m1[i, j] = random.Next(-100, 100); } } Matrix m2 = new Matrix(30, 40); for (int i = 0; i < m2.Height; i++) { for (int j = 0; j < m2.Width; j++) { m2[i, j] = random.Next(-100, 100); } } Console.WriteLine(Measure(() => Matrix.NaiveMultiplication(m1, m2), 10000)); Console.WriteLine(Measure(() => Matrix.UnsafeMultiplication(m1, m2), 10000)); } }

In this test we perform 10000 multiplications of two randomly generated matrices with sizes 20×30 and 30×40 using both methods:

Method |
CPU cycles |

unsafe multiplication | 4485698 |

naive multiplication | 58762273 |

The results show that the naive multiplication is slower by a factor of 13 compared to the multiplication using unsafe code and working directly with memory.

## 2 thoughts on “Fun with matrix multiplication and unsafe code”

Multi dimensional arrays in C# are slow. The safe version from this article

https://www.daniweb.com/software-development/csharp/code/355645/optimizing-matrix-multiplication

is 1.5 times faster than this unsafe, even with one thread.

Who can healp me

Please

.

.

For a matrix M * N

You must write a class with the following characteristics:

1. Have a function

2-have a constraint to get the matrix dimension

3-You can add or split 2 objects from the matrix class

4. There is a print function to print the matrix

5. It has an index function, that is, it can be accessed by its array as a two-dimensional array via {}