Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вычисление определителя матрицы любой размерности

7
07 марта 2010 года
@pixo $oft
3.4K / / 20.09.2006
Хочу представить вашему вниманию свою программу(нет,за меня её делать не надо:)).Пока что она немного ограничена,но может вычислять определители матриц с положительными и отрицательными элементами в теоретическом пределе ±32767(практически лучше не брать значения,по модулю большие 256)

У меня просьба–проверить код сначала визуально(если кому-то не лень:)),а затем в деле.Мои тесты(с матрицами размера 0..5) он прошёл без проблем(сверялся с MathCAD'ом)

Синтаксис процедуры прост:1й параметр–указатель на матрицу двойных слов(матрица располагается в памяти линейно по строкам),2й–размерность матрицы.На выходе–определитель заданной матрицы

В аттаче приведены коды для .exe и .dll,а также сама библиотека и файл .lib(если вы линковать вдруг будете;например,у вас нет асма и вы будете тестировать на C++)

Также буду рад замечаниям по улучшению кода,вашим кодам вычисления определителя(если вы делали);желательно на асме,конечно,C/Delphi/VB в крайнем случае.Если есть какие-то более лёгкие и быстрые методы–с радостью рассмотрю

Если возникнут какие-то вопросы типа как пользоваться,объяснить структуру или зачем ТС это понадобилось–милости просим (= Постараюсь всё разъяснить
8.4K
07 марта 2010 года
z0rch
275 / / 02.09.2008
updated:да, теперь есть, можно посмотреть..:)
7
07 марта 2010 года
@pixo $oft
3.4K / / 20.09.2006
[COLOR="Silver"]OH SHI--!!!
Не знаю,куда он подевался,вроде цеплял.Но теперь он точно есть,поэтому прошу по возможности(по желанию:)) почистить свои мессаги и приступить к делу

Proger_XP :)[/COLOR]

Upd:вот и отлично.Буду рад содействию в тестировании и совершенствовании.Просто это вроде как 1й мой проект,который можно совместить с учёбой(предыдущее всё было только для себя,в основном;в смысле,с учёбой не связанное)
8.4K
08 марта 2010 года
z0rch
275 / / 02.09.2008
@pixo $oft, а можешь рассказать вкратце суть, как ты определитель считаешь?
(честно сказать, с ассемблером еще не сталкивался, сейчас скачал masm (надеюсь я угадал что скачать?), пока что остановился на ошибке
fatal error RC1110 : could not open rsrc.rc
завтра продолжу бороться с ним))
ну не в этом суть.
я недавно писал подсчет определителя, алгоритм такой:

Приводим матрицу к единичному виду (главная диагональ состоит из 1, под ней нули, над ней (в этом случае) неважно что)
[COLOR="DimGray"]Как приводить: берем элемент [1][1], если он не равен нулю, то делим строку с этим элементом на него же, и сохраняем этот элемент в отдельной переменной(т.е выносим как бы за скобку), от остальных строк(можно от строк, стоящих "ниже" текущей) отнимаем эту строку умноженную на элемент [1]. получаем столбец (1,0,0...0). идем на [2][2] и повторяем действия.... Если, например, перебором по [1] не нашли элемента, отличного от нуля, то определитель соотв. равен нулю. [/COLOR]
"Вынесенные элементы" потом перемножаем и получаем определитель матрицы.
p.s. ну и не забываем, если элемент отрицателен, то можно умножить строку на -1, и вынесенный коэфициент умножить на -1.

код: (с++, признаюсь он не совершенен)
Код:
double opred(int n,long double matr[MAX][MAX])
{
    j1=0;j=0;
    for(i=0;i<n;i++)
    {
        if(str==0)
        {
            if(matr[j] != 0)
            {
                if(matr[j] < 0)
                {
                    for(j1=0;j1<n;j1++)
                    matr[j1]=matr[j1]*(-1);
                    koef=koef*(-1);
                }
                str=i;
                koef=koef*matr[j];
                k=matr[j];
                for(j1=0;j1<n;j1++)
                    matr[j1]=matr[j1]/k;
                j1=j;i1=i+1;
                while(i1<n)
                {
                    k=matr[i1][j1];
                    for(;j1<n;j1++)
                        matr[i1][j1]=matr[i1][j1]-k*matr[j1];
                    i1++;j1=j;
                }
                str=0;j=i+1;flag=false;
            }
            else
            {
                for(j1=0;j1<n;j1++)
                    swap(matr[j1],matr[n-1][j1]);
                i--;koef=koef*(-1);
                if(flag)
                {
                    i++;koef=0;
                }
                flag=true;
            }
        }
    }
    return koef;
};


забыл добавить: чем этот алгоритм плох - я постоянно делю дробное число на дробное, отсюда неточность, если она принципиально важна - мой алгоритм не катит
7
08 марта 2010 года
@pixo $oft
3.4K / / 20.09.2006
Рад,что откликнулся:)
Цитата: z0rch
…(надеюсь я угадал что скачать?), пока что остановился на ошибке
fatal error RC1110 : could not open rsrc.rc

Угадал-угадал (=
Это при компиляции ошибка?Ну так у меня нет файла ресурсов,а в командной строке у тебя наверняка указана эта опция;)

Цитата: z0rch
…а можешь рассказать вкратце суть, как ты определитель считаешь?

Вполне могу.Считаю я его стандартным алгоритмом,через миноры.Т.е. в лоб с рекурсией;насколько я понимаю,это долго…но до других методов я пока не дошёл:)

Цитата: z0rch
чем этот алгоритм плох - я постоянно делю дробное число на дробное, отсюда неточность, если она принципиально важна - мой алгоритм не катит

Дело в том,что работать с вещественными числами на асме я пока не умею.Да и код твой,ИМХО,великоват для меня(нет,не в смысле он у тебя плохой…просто на асме это будет что-то=)).Поэтому он мне пока не подходит…но в будущем надеюсь его рассмотреть,особенно если он будет быстрее моего
В любом случае,спасибо за ответ

8.4K
08 марта 2010 года
z0rch
275 / / 02.09.2008
Цитата: @pixo $oft
Это при компиляции ошибка?Ну так у меня нет файла ресурсов,а в командной строке у тебя наверняка указана эта опция;)


да, скорее всего ты прав =)

Цитата: @pixo $oft
Да и код твой,ИМХО,великоват для меня…просто на асме это будет что-то=))


Ну да, я представляю...))

Цитата: @pixo $oft
[COLOR="SlateGray"]но в будущем надеюсь его рассмотреть,[/COLOR]особенно если он будет быстрее моего


он будет быстрее если я сразу же найду столбец в нулями, тогда цикл завершится и ответ - 0. А в других случаях врядли он будет быстрее, мне понравился просто "необычный, нестандартный я б сказал" подход =)

7
08 марта 2010 года
@pixo $oft
3.4K / / 20.09.2006
Цитата: z0rch
мне понравился просто "необычный, нестандартный я б сказал" подход =)

Это откуда такая фраза?:) Про твой метод,я так понимаю

Кстати,в аттаче есть ещё DLL(ну ты видел:)),так вот,чтобы не заморачиваться с компиляцией кода,просто воспользуйся DLL.Синтаксис я написал
Для начала проверь на простых матрицах–от 1 до 3,а уж потом можно и посложнее.Я вот проверял на 8x8,пока работает:rolleyes:

8.4K
08 марта 2010 года
z0rch
275 / / 02.09.2008
Цитата: @pixo $oft
Это откуда такая фраза?:) Про твой метод,я так понимаю


ну да, я непонятно выразился :) просто наблюдал, кто как пишет(даже просто как считают в тетрадке), большинство людей идут простым разложением по первой(чаще всего) строчке, и не заморачиваются.
а тут идея интересная - выносить множитель и приводить к единичной матрице...

Цитата: @pixo $oft
Кстати,в аттаче есть ещё DLL(ну ты видел:)),так вот,чтобы не заморачиваться с компиляцией кода,просто воспользуйся DLL.Синтаксис я написал
Для начала проверь на простых матрицах–от 1 до 3,а уж потом можно и посложнее.Я вот проверял на 8x8,пока работает:rolleyes:


окей, посмотрю, потом отпишусь =)

7
12 марта 2010 года
@pixo $oft
3.4K / / 20.09.2006
Ах да,небольшое дополнение…(выяснилось во время онлайн-тестирования:))
Т.к. автор сей программы(т.е. я) поместил код и данные в одну секцию(кода;в самом деле,зачем под небольшое количество данных новую секцию?),при линковке следует установить атрибут секции .text,разрешающий запись в неё,так-то.А то мы на пару с z0rch'ем долго думали,почему он ловит AW,в то время как у меня всё отлично (=
8.4K
20 марта 2010 года
z0rch
275 / / 02.09.2008
продолжение этого сериала - рекурсивный подсчет определителя на с++.
[COLOR="SlateGray"]подскажите, пожалуйста, в чем здесь ошибка?
( уже сил нет, замучал и себя, и топикстартера :D )[/COLOR]
после долгих мучений, благодаря @pixo $oft, решение было найдено.
Код:
int det(int aa[10][10],int n)
{
[COLOR="Red"]        int d=0;//а не глобально!!![/COLOR]
    int b[10][10];
    if(n==2)
    {
        return (aa[0][0]*aa[1][1]-aa[0][1]*aa[1][0]);
    }

   
   for(int i=0;i<n;i++)
   {
    for(int y=1; y<n; y++)
            for(int x=0; x<n; x++)
            {
                if(x==i) continue;
                if(x<i)
                    b[y-1][x] = aa[y][x];
                else
                    b[y-1][x-1] = aa[y][x];
            }
        d+=pow(-1,(double)(2+i))*aa[0]*det(b,n-1);
   }

   return d;
}
842
20 марта 2010 года
sigmov
301 / / 16.09.2008
Я тоже с Ассемблером плотно не работал....

Но недавно как раз писал библиотеку для матричных вычислений
(быстрых, а не просто, чтоб ситалось)

Вообщем пришел к выводу что самый быстрый(по скорости) способ работы с матрицами, это хранение матрицы в непрерывном массиве T*, а не T** и работа с ней через указатели.

Определитель расчитывается методом Гаусса с выбором ведущего по столбцу.

И вот результат:
Код:
//Детерминант матрицы
    inline double det(CMatrix<double> mtx)
    {
        SafeRankVec(mtx.rows,mtx.cols); //Проверка квадратности
        bool sgn = true;
        double *_IT_begin = mtx._begin(), *_IT_end = _IT_begin + mtx.cols*mtx.cols;
        double *_IT_ii = _IT_begin, *_IT_ii_end = _IT_ii+mtx.cols;
        double determ = 1.0;
        for(int d = mtx.cols;_IT_ii<_IT_end; determ*=*_IT_ii, _IT_ii+=mtx.cols+1, _IT_ii_end+=mtx.cols, d--)
        {
            double *_mx = mem::nmax_abs(_IT_ii,mtx.cols,d);     //ищем максимальный элемент в столбце
            if(abs(*_mx) < dEps) return 0.0;
            else
                if(_mx!=_IT_ii)
                {
                    mem::nmemswap(_IT_ii,_mx,d);                //замена строк
                    sgn = !sgn;
                }
            for(double *_IT_i=_IT_ii+mtx.cols;_IT_i<_IT_end;_IT_i+=mtx.cols)
                for(register double a = *_IT_i / *_IT_ii, *_IT_ii_j = _IT_ii + 1, *_IT_i_j = _IT_i + 1; _IT_ii_j<_IT_ii_end; *(_IT_i_j++)-= *(_IT_ii_j++) * a);
        }
        if(sgn) return determ;
        else return -determ;
    }


К сожалению у данного кода существенный недостаток: он просто жуть как нечитаем ))). Даже мне чтоб вспомнить что там за что отвечает - понадобиться много времени.

Зато он даже LAPAC обгоняет по скорости.
76K
10 января 2012 года
АллаКо
1 / / 17.10.2011
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace lab1
{
class Matrix
{
public int row, col;
public int[,] p;
double det;

public Matrix(int n, int m)
{
row = n;
col = m;
p = new int[n, m];
}

public void InitMartix() // Ввод матрицы
{
Random aa = new Random();
for (int i = 0; i < row; i++)
for (int j = 0; j < row; j++)
{

p[i, j] = aa.Next(5);
}
}


public double Det2x2()
{
double det;
det = p[0, 0] * p[1, 1] - p[0, 1] * p[1, 0];

return det;
} //Det 2x2

public void ShowMartix() //Вывод матрицы
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < row; j++)
{
Console.Write(p[i, j]);
Console.Write(" ");
}
Console.WriteLine();
}
}
//Минор
public Matrix Menor(int a, int b)
{
int i, j, p, q;
Matrix MEN = new Matrix(row - 1, col - 1);
for (j = 0, q = 0; q < MEN.col; j++, q++)
for (i = 0, p = 0; p < MEN.row; i++, p++)
{
if (i == a) i++;
if (j == b) j++;
MEN.p[p, q] = this.p[i, j];
}
return MEN;
}

//Определитель матрицы
public static double Det(Matrix B)
{
int n;
int signo;
double det = 0;

if (B.row != B.col)
{
Console.WriteLine("Matritsa dolgna biti kvadratnoi");
return 0;
}
else
if (B.row == 1)
return B.p[0, 0];
else
if (B.row == 2)
return B.Det2x2();
else
for (n = 0; n < B.col; n++)
{ //Проверка на знак
if ((n & 1) == 0)
{
signo = 1;
}
else
{
signo = -1;
}
//(n&1)==0 ? (signo=1):(signo=-1);
det = det + signo * B.p[0, n] * Det(B.Menor(0, n));
}

return det;
}
}


class Program
{
static void Main(string[] args)
{
Console.WriteLine("Введите размерность первой матрицы: ");
int[,] A = new int[Convert.ToInt32(Console.ReadLine()), Convert.ToInt32(Console.ReadLine())];
Matrix m = new Matrix(A.GetLength(0), A.GetLength(0));
m.InitMartix();
Console.WriteLine("Matrix");
m.ShowMartix();
Console.WriteLine();
Console.Write("Det = ");
Console.Write(Matrix.Det(m));
Console.WriteLine();
Console.ReadKey();
}
}
}
На сишарпе-вычислит любой тебе определитель-главное не тупить))
278
10 января 2012 года
Alexander92
1.1K / / 04.08.2008
[QUOTE=АллаКо]
 
Код:
Matrix MEN = new Matrix(row - 1, col - 1);

[/QUOTE]
Это очень круто, особенно когда речь как раз идет о скорости расчета... Ну а если на даты посмотреть, можно вообще порадоваться. :)

[QUOTE=АллаКо]
главное не тупить))
[/QUOTE]
Эх... Золотые слова! :)
277
10 января 2012 года
arrjj
1.7K / / 26.01.2011
Рекурсивно вычислять определитель матрици - зло.
7
10 января 2012 года
@pixo $oft
3.4K / / 20.09.2006
Цитата: Alexander92
если на даты посмотреть, можно вообще порадоваться

В свете текущих событий я вовсе не против возрождения данной темы ☺

arrjj,какие будут варианты?;)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог