2d-Array with more than 65535^2 elements --> Array dimensions exceeded supported range

前端 未结 2 395
南笙
南笙 2020-12-11 06:24

I\'ve a 64-bit PC with 128 GB of RAM and I\'m using C# and .NET 4.5. I\'ve the following code:

double[,] m1 = new double[65535, 65535];
long l1 = m1.LongLeng         


        
2条回答
  •  执念已碎
    2020-12-11 06:33

    I've used the basic example of the "Marshal" approach from this answer from MrPaulch to create the following class called HugeMatrix:

    public class HugeMatrix : IDisposable
        where T : struct
    {
        public IntPtr Pointer
        {
            get { return pointer; }
        }
    
        private IntPtr pointer = IntPtr.Zero;
    
        public int NRows
        {
            get { return Transposed ? _NColumns : _NRows; }
        }
    
        private int _NRows = 0;
    
        public int NColumns
        {
            get { return Transposed ? _NRows : _NColumns; }
        }
    
        private int _NColumns = 0;
    
        public bool Transposed
        {
            get { return _Transposed; }
            set { _Transposed = value; }
        }
    
        private bool _Transposed = false;
    
        private ulong b_element_size = 0;
        private ulong b_row_size = 0;
        private ulong b_size = 0;
        private bool disposed = false;
    
    
        public HugeMatrix()
            : this(0, 0)
        {
        }
    
        public HugeMatrix(int nrows, int ncols, bool transposed = false)
        {
            if (nrows < 0)
                throw new ArgumentException("The number of rows can not be negative");
            if (ncols < 0)
                throw new ArgumentException("The number of columns can not be negative");
            _NRows = transposed ? ncols : nrows;
            _NColumns = transposed ? nrows : ncols;
            _Transposed = transposed;
            b_element_size = (ulong)(Marshal.SizeOf(typeof(T)));
            b_row_size = (ulong)_NColumns * b_element_size;
            b_size = (ulong)_NRows * b_row_size;
            pointer = Marshal.AllocHGlobal((IntPtr)b_size);
            disposed = false;
        }
    
        public HugeMatrix(T[,] matrix, bool transposed = false)
            : this(matrix.GetLength(0), matrix.GetLength(1), transposed)
        {
            int nrows = matrix.GetLength(0);
            int ncols = matrix.GetLength(1);
            for (int i1 = 0; i1 < nrows; i1++)
                for (int i2 = 0; i2 < ncols; i2++)
                    this[i1, i2] = matrix[i1, i2];
        }
    
        public void Dispose()
        {
            if (!disposed)
            {
                Marshal.FreeHGlobal(pointer);
                _NRows = 0;
                _NColumns = 0;
                _Transposed = false;
                b_element_size = 0;
                b_row_size = 0;
                b_size = 0;
                pointer = IntPtr.Zero;
                disposed = true;
            }
        }
    
        public void Transpose()
        {
            _Transposed = !_Transposed;
        }
    
        public T this[int i_row, int i_col]
        {
            get
            {
                IntPtr p = getAddress(i_row, i_col);
                return (T)Marshal.PtrToStructure(p, typeof(T));
            }
            set
            {
                IntPtr p = getAddress(i_row, i_col);
                Marshal.StructureToPtr(value, p, true);
            }
        }
    
        private IntPtr getAddress(int i_row, int i_col)
        {
            if (disposed)
                throw new ObjectDisposedException("Can't access the matrix once it has been disposed");
            if (i_row < 0)
                throw new IndexOutOfRangeException("Negative row indices are not allowed");
            if (i_row >= NRows)
                throw new IndexOutOfRangeException("Row index is out of bounds of this matrix");
            if (i_col < 0)
                throw new IndexOutOfRangeException("Negative column indices are not allowed");
            if (i_col >= NColumns)
                throw new IndexOutOfRangeException("Column index is out of bounds of this matrix");
            int i1 = Transposed ? i_col : i_row;
            int i2 = Transposed ? i_row : i_col;
            ulong p_row = (ulong)pointer + b_row_size * (ulong)i1;
            IntPtr p = (IntPtr)(p_row + b_element_size * (ulong)i2);
            return p;
        }
    }
    

    and I can call now the Intel MKL library with huge matrices, e.g.:

    [DllImport("custom_mkl", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, SetLastError = false)]
    internal static extern lapack_int LAPACKE_dsyevd(
        int matrix_layout, char jobz, char uplo, lapack_int n, [In, Out] IntPtr a, lapack_int lda, [In, Out] double[] w);
    

    For the argument IntPtr a I pass the Pointer property of the HugeMatrix class.

提交回复
热议问题