Возведение большой матрицы, читаемой с файла, в степень N, и запись обратно в файл на C#

Узнай цену своей работы

Формулировка задачи:

Доброго времени. Очень нужно написать программу на C#, которая прочитает с файла огромную матрицу с вещественными числами (допустим, 1000 на 1000), возвести её в степень N, и результат записать в новый файл. Вот так... Думал, сам напишу, убил кучу времени, и теперь, от безысходности, пишу тут. Помогите пожалуйста. За ранее благодарен всем, кто уделит время. И с Рождеством всех, ребята. =) P.S.: это нужно делать в консольном приложении. Очень срочно.
Пример матрицы тут можно взять (363х363): http://rghost.ru/60192711

Решение задачи: «Возведение большой матрицы, читаемой с файла, в степень N, и запись обратно в файл на C#»

textual
Листинг программы
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
 
namespace ConsoleApplication18
{
    public class Matrix : IEnumerable<double>
    {
        const string DimentionExceptionMessage = "Invalid matrix dimensions";
        public static Matrix GetE(int n)
        {
            var result = new Matrix(n, n);
            for (int i = 0; i < n; i++)
            {
                result[i, i] = 1.0;
            }
            return result;
        }
 
        private readonly double[,] _value;
 
        public Matrix(int rows, int cols)
            : this(new double[rows, cols])
        {
        }
 
        public Matrix(double[,] value)
        {
            _value = (double[,])value.Clone();
        }
 
        public static Matrix operator *(Matrix one, Matrix other)
        {
            return new Matrix(Multiply(one._value, other._value));
        }
 
        public static Matrix operator *(double scalar, Matrix matrix)
        {
            var result = (double[,])matrix._value.Clone();
            for (int i = 0; i < result.GetLength(0); i++)
            {
                for (int j = 0; j < result.GetLength(1); j++)
                {
                    result[i, j] *= scalar;
                }
            }
            return result;
        }
 
        public static Matrix operator *(Matrix matrix, double scalar)
        {
            return scalar * matrix;
        }
 
        public static Matrix operator +(Matrix one, Matrix another)
        {
            return MatrixSum(one, another, 1);
        }
 
        public static Matrix operator -(Matrix one, Matrix another)
        {
            return MatrixSum(one, another, -1);
        }
 
        private static Matrix MatrixSum(Matrix one, Matrix another, int sign)
        {
            var m = GetDim(one, another, 0);
            int n = GetDim(one, another, 1);
            var res = new double[m, n];
            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    res[i, j] = one[i, j] + another[i, j] * sign;
                }
            }
            return new Matrix(res);
        }
 
        private static int GetDim(Matrix one, Matrix another, int dim)
        {
            int dimOne = one._value.GetLength(dim);
            int dimAnother = another._value.GetLength(dim);
 
            if (dimOne != dimAnother)
                throw new ArgumentException(DimentionExceptionMessage);
            return dimOne;
        }
 
        private int GetDimIfSquare()
        {
            int x = _value.GetLength(0);
            int y = _value.GetLength(1);
            if (x != y)
                throw new ArgumentException(DimentionExceptionMessage);
            return x;
        }
 
        public static Matrix operator /(Matrix matrix, double scalar)
        {
            return matrix * (1.0 / scalar);
        }
 
        public double this[int i, int j]
        {
            get { return _value[i, j]; }
            set { _value[i, j] = value; }
        }
 
        public IEnumerator<double> GetEnumerator()
        {
            // ReSharper disable once LoopCanBeConvertedToQuery
            foreach (double d in _value)
            {
                yield return d;
            }
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
 
        public static implicit operator Matrix(double[,] doubles)
        {
            return new Matrix(doubles);
        }
 
        public static explicit operator double[,](Matrix matrix)
        {
            return matrix._value;
        }
        public int GetLength(int dim)
        {
            return _value.GetLength(dim);
        }
 
        private static double[,] Multiply(double[,] a, double[,] b)
        {
            if (a.GetLength(1) != b.GetLength(0))
                throw new ArgumentException(DimentionExceptionMessage);
            return SafeMultiply(a, b, a.GetLength(0), b.GetLength(1), a.GetLength(1));
        }
 
 
        public Matrix Pow(int power)
        {
            int dim = GetDimIfSquare();
            var result = GetE(dim)._value;
            var tmp = _value;
            while (power != 0)
            {
                if (power % 2 != 0)
                {
                    result = SafeMultiply(tmp, result, dim, dim, dim);
                    power -= 1;
                }
                tmp = SafeMultiply(tmp, tmp, dim, dim, dim);
                power /= 2;
            }
            return result;
        }
 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static double[,] SafeMultiply(double[,] a, double[,] b, int imax, int jmax, int kmax)
        {
            double[,] c = new double[imax, jmax];
            int blockCount = Environment.ProcessorCount;
            int blockSize = (int) Math.Ceiling((double) jmax/blockCount);
            int completedBlocks = 0;
            var reset = new ManualResetEvent(false);
            for (int block = 0; block < blockCount; block++)
            {
                int from = block*blockSize;
                int to = Math.Min(from + blockSize, jmax);
                ThreadPool.QueueUserWorkItem(state =>
                {
                    var bcolj = new double[kmax];
                    for (int j = from; j < to; j++)
                    {
                        for (var k = 0; k < kmax; k++)
                            bcolj[k] = b[k, j];
 
                        for (var i = 0; i < imax; i++)
                        {
                            double s = 0;
                            for (var k = 0; k < kmax; k++)
                                s += a[i, k] * bcolj[k];
                            c[i, j] = s;
                        }
                    }
                    if (Interlocked.Increment(ref completedBlocks) == blockCount)
                    {
                        reset.Set();
                    }
                });
            }
            reset.WaitOne();
            return c;
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

12   голосов , оценка 3.667 из 5
Похожие ответы