Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.96/190: Рейтинг темы: голосов - 190, средняя оценка - 4.96
0 / 0 / 0
Регистрация: 08.11.2010
Сообщений: 9

Найти обратную матрицу и умножить ее на вектор

08.11.2010, 20:49. Показов 40233. Ответов 25
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Очень нужна помощь для нахождения обратной матрицы на С++.
Дело в том что мне нужно реализовать такую задачу:
найти обратную матрицу и умножить ее на вектор.
каким методом лучше находить обратную матрицу и какой алгоритм нахождения...помогите пожалуйста.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.11.2010, 20:49
Ответы с готовыми решениями:

в матрице А(n x m) найти первый столбец, не содержащий отрицательных элементов, и умножить его как вектор на матрицу А
2. в матрице А(n x m) найти первый столбец, не содержащий отрицательных элементов, и умножить его как вектор на матрицу А заранее...

Умножить вектор-строку на матрицу
Есть вектор-строка размера 1*6, её надо умножить на матрицу размером 6*27. Не понимаю как сделать такое умножение. Сколько не пробовал не...

Умножить матрицу квадратную на вектор
уже не знаю, что делать до ужаса глупейшая ошибка, из-за чего весь алгоритм к чертям:( for (int i = 1; i < size; i++) for...

25
60 / 60 / 17
Регистрация: 12.10.2010
Сообщений: 129
08.11.2010, 20:52
Метод Гаусса—Жордана
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
09.11.2010, 00:14
Лучший ответ Сообщение было отмечено как решение

Решение

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <iostream>
 
void inversion(double **A, int N)
{
    double temp;
 
    double **E = new double *[N];
 
    for (int i = 0; i < N; i++)
        E[i] = new double [N];
 
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
        {
            E[i][j] = 0.0;
 
            if (i == j)
                E[i][j] = 1.0;
        }
 
    for (int k = 0; k < N; k++)
    {
        temp = A[k][k];
 
        for (int j = 0; j < N; j++)
        {
            A[k][j] /= temp;
            E[k][j] /= temp;
        }
 
        for (int i = k + 1; i < N; i++)
        {
            temp = A[i][k];
 
            for (int j = 0; j < N; j++)
            {
                A[i][j] -= A[k][j] * temp;
                E[i][j] -= E[k][j] * temp;
            }
        }
    }
 
    for (int k = N - 1; k > 0; k--)
    {
        for (int i = k - 1; i >= 0; i--)
        {
            temp = A[i][k];
 
            for (int j = 0; j < N; j++)
            {
                A[i][j] -= A[k][j] * temp;
                E[i][j] -= E[k][j] * temp;
            }
        }
    }
 
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            A[i][j] = E[i][j];
 
    for (int i = 0; i < N; i++)
        delete [] E[i];
 
    delete [] E;
}
 
int main()
{
    int N;
 
    std::cout << "Enter N: ";
    std::cin >> N;
 
    double **matrix = new double *[N];
 
    for (int i = 0; i < N; i++)
        matrix[i] = new double [N];
 
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
        {
            std::cout << "Enter matrix[" << i << "][" << j << "] = ";
            std::cin >> matrix[i][j];
        }
 
    inversion(matrix, N);
 
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
            std::cout << matrix[i][j] << "  ";
 
        std::cout << std::endl;
    }
 
    for (int i = 0; i < N; i++)
        delete [] matrix[i];
 
    delete [] matrix;
 
    std::cin.get();
    return 0;
}
23
0 / 0 / 0
Регистрация: 08.11.2010
Сообщений: 9
09.11.2010, 00:26  [ТС]
а можно написать коротко алгоритм этой проги....какую максимальную матрицу она может расчитать..
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
09.11.2010, 00:35
На счёт максимальной не знаю... Думаю, ограничение идёт только по доступной памяти. А алгоритм основан на методе Гаусса (вернее на его модификации - метода Гаусса-Жордана - т.н. методе полного исключения неизвестных). Мы просто-напросто с помощью элементарных преобразований приводим начальную матрицу к единичной. А вся фишка в том, что если те же преобразования в том же порядке применить к единичной матрице - получим матрицу, обратную для начальной.
0
0 / 0 / 0
Регистрация: 08.11.2010
Сообщений: 9
09.11.2010, 00:38  [ТС]
а этод метод можно распаралелить через портфель задач и мютексы?а потом еще и умножить на вектор?

Добавлено через 1 минуту
и на счет метода:
не могу найти нормальный словесный алгорит, что умножаем что делим и вычитаем...
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
09.11.2010, 00:39
Ух ты, вот это спросили))) Я не в курсе, параллельным программированием никогда не занимался... По идее тут цикл, поэтому чисто теоретически распараллелить можно... Но вот как - это уже вопрос не ко мне.
Ну а кто мешает умножить матрицу на вектор? По-моему никто.
0
0 / 0 / 0
Регистрация: 08.11.2010
Сообщений: 9
09.11.2010, 00:41  [ТС]
а можете хотя бы на словах описать программу.
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
09.11.2010, 00:42
http://ru.wikipedia.org/wiki/М... _—_Жордана
1
Irkira
24.01.2012, 11:01
Метод Гаусса—Жордана
silent_1991, спасибо за код, очень помог
0 / 0 / 1
Регистрация: 18.03.2012
Сообщений: 22
20.04.2012, 03:47
да, спасибо)
пожалуй единственная прога просто реализованная, и хорошо работающая из тех что лежат в нете
0
108 / 108 / 23
Регистрация: 21.03.2010
Сообщений: 445
12.09.2012, 13:20
Котаны, автозаменой переделал под Qt...
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
template <int N, typename T> QGenericMatrix<N,N,T> invert(QGenericMatrix<N,N,T> matrix)
{
    T temp;
 
    QGenericMatrix<N,N,T> ret;
    ret.setToIdentity();
    T* rM = ret.data();
    T* sM = matrix.data();
 
 
 
    for (int k = 0; k < N; k++)
    {
        temp = sM[k + k * N];
 
        for (int j = 0; j < N; j++)
        {
            sM[k + j * N] /= temp;
            rM[k + j * N] /= temp;
        }
 
        for (int i = k + 1; i < N; i++)
        {
            temp = sM[i + k * N];
 
            for (int j = 0; j < N; j++)
            {
                sM[i + j * N] -= sM[k + j * N] * temp;
                rM[i + j * N] -= rM[k + j * N] * temp;
            }
        }
    }
 
    for (int k = N - 1; k > 0; k--)
    {
        for (int i = k - 1; i >= 0; i--)
        {
            temp = sM[i + k * N];
 
            for (int j = 0; j < N; j++)
            {
                sM[i + j * N] -= sM[k + j * N] * temp;
                rM[i + j * N] -= rM[k + j * N] * temp;
            }
        }
    }
    return ret;
}
Добавлено через 23 минуты
Ну и до кучи коротенький пример решения СЛАУ н-ого порядка:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
    QGenericMatrix<2,2,qreal> matrix;
    matrix(0,0) = 1;
    matrix(0,1) = 7;
    matrix(1,0) = 1;
    matrix(1,1) = 2;
    QGenericMatrix<1,2,qreal> b;
    b(0,0) = 9;
    b(1,0) = 4;
 
    QGenericMatrix<1,2,qreal> solution = invert(matrix) * b;
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
16.11.2012, 02:09
Мне тут в личке сообщили о баге, выкладываю новую версию обращения матрица. Писал тоже давно, особо не тестировал, так что баги также не исключены.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <cmath>
 
// Функция, производящая обращение матрицы.
// Принимает:
//     matrix - матрица для обращения
//     result - матрица достаточного размера для вмещения результата
//     size   - размерность матрицы
// Возвращает:
//     true в случае успешного обращения, false в противном случае
bool inverse(double **matrix, double **result, int size)
{   
    // Изначально результирующая матрица является единичной
    // Заполняем единичную матрицу
    for (int i = 0; i < size; ++i)
    {
        for (int j = 0; j < size; ++j)
            result[i][j] = 0.0;
        
        result[i][i] = 1.0;
    }
    
    // Копия исходной матрицы
    double **copy = new double *[size]();
    
    // Заполняем копию исходной матрицы
    for (int i = 0; i < size; ++i)
    {
        copy[i] = new double [size];
        
        for (int j = 0; j < size; ++j)
            copy[i][j] = matrix[i][j];
    }
    
    // Проходим по строкам матрицы (назовём их исходными)
    // сверху вниз. На данном этапе происходит прямой ход
    // и исходная матрица превращается в верхнюю треугольную
    for (int k = 0; k < size; ++k)
    {
        // Если элемент на главной диагонали в исходной
        // строке - нуль, то ищем строку, где элемент
        // того же столбца не нулевой, и меняем строки
        // местами
        if (fabs(copy[k][k]) < 1e-8)
        {
            // Ключ, говорязий о том, что был произведён обмен строк
            bool changed = false;
            
            // Идём по строкам, расположенным ниже исходной
            for (int i = k + 1; i < size; ++i)
            {
                // Если нашли строку, где в том же столбце
                // имеется ненулевой элемент
                if (fabs(copy[i][k]) > 1e-8)
                {
                    // Меняем найденную и исходную строки местами
                    // как в исходной матрице, так и в единичной
                    std::swap(copy[k],   copy[i]);
                    std::swap(result[k], result[i]);
                    
                    // Взводим ключ - сообщаем о произведённом обмене строк
                    changed = true;
                    
                    break;
                }
            }
            
            // Если обмен строк произведён не был - матрица не может быть
            // обращена
            if (!changed)
            {
                // Чистим память
                for (int i = 0; i < size; ++i)
                    delete [] copy[i];
                
                delete [] copy;
                
                // Сообщаем о неудаче обращения
                return false;
            }
        }
        
        // Запоминаем делитель - диагональный элемент
        double div = copy[k][k];
        
        // Все элементы исходной строки делим на диагональный
        // элемент как в исходной матрице, так и в единичной
        for (int j = 0; j < size; ++j)
        {
            copy[k][j]   /= div;
            result[k][j] /= div;
        }
        
        // Идём по строкам, которые расположены ниже исходной
        for (int i = k + 1; i < size; ++i)
        {
            // Запоминаем множитель - элемент очередной строки,
            // расположенный под диагональным элементом исходной
            // строки
            double multi = copy[i][k];
            
            // Отнимаем от очередной строки исходную, умноженную
            // на сохранённый ранее множитель как в исходной,
            // так и в единичной матрице
            for (int j = 0; j < size; ++j)
            {
                copy[i][j]   -= multi * copy[k][j];
                result[i][j] -= multi * result[k][j];
            }
        }
    }
    
    // Проходим по вернхней треугольной матрице, полученной
    // на прямом ходе, снизу вверх
    // На данном этапе происходит обратный ход, и из исходной
    // матрицы окончательно формируется единичная, а из единичной -
    // обратная
    for (int k = size - 1; k > 0; --k)
    {
        // Идём по строкам, которые расположены выше исходной
        for (int i = k - 1; i + 1 > 0; --i)
        {
            // Запоминаем множитель - элемент очередной строки,
            // расположенный над диагональным элементом исходной
            // строки
            double multi = copy[i][k];
            
            // Отнимаем от очередной строки исходную, умноженную
            // на сохранённый ранее множитель как в исходной,
            // так и в единичной матрице
            for (int j = 0; j < size; ++j)
            {
                copy[i][j]   -= multi * copy[k][j];
                result[i][j] -= multi * result[k][j];
            }
        }
    }
    
    // Чистим память
    for (int i = 0; i < size; ++i)
        delete [] copy[i];
    
    delete [] copy;
    
    // Сообщаем об успехе обращения
    return true;
}
5
 Аватар для AlexP11223
141 / 110 / 30
Регистрация: 20.04.2011
Сообщений: 582
16.11.2012, 11:11
А проверка обмена строк (changed) зачем? Если детерминант всегда не 0, то он не нужен?
0
Антикодер
Эксперт функциональных языков программирования
1888 / 870 / 48
Регистрация: 15.09.2012
Сообщений: 3,088
16.11.2012, 11:38
а этод метод можно распаралелить через портфель задач и мютексы?а потом еще и умножить на вектор?
а вы супер компьютер строите?

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

а распределять мат вычисления в железе это задача не для новичков, думаю что есть смысл посмотреть это
http://ru.wikipedia.org/wiki/I... ing_Blocks
(в том смысле, что кто лучше интела сможет работать с их процом?)

возможно видяху тоже можно как то подключить для мат вычислений.

в любой случае надо сначала посчитать программно сколько времени вы теряете на каждом цикле

мьютекс это просто ограничитель для использования данных

Добавлено через 15 минут
в параллельном программировании у меня маленький опыт, но думаю это делается так
надо для начала разбить долгие вычисления на две части, у которых есть что то на входе и выходе.
Получается например две задачи будут выполнять сложные вычисления, третья будет делать остальные вычисления и четвертая задача может ожидать например от пользователя отмены вычислений.

Все данные которые мы получаем в первом потоке мы не напрямую отправляем во второй поток, а пользуемся конструкцией типа почтового ящика которая отправляет сообщения, и в сообщении просто указываем адрес где находится результат.
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
16.11.2012, 16:15
Цитата Сообщение от AlexP11223 Посмотреть сообщение
Если детерминант всегда не 0, то он не нужен?
Если уверены, что матрица не вырожденная - проверка не нужна. Но лучше её всё же оставить (я бы оставил), универсальность никогда не повредит.
0
 Аватар для Ternsip
670 / 198 / 29
Регистрация: 10.05.2012
Сообщений: 595
07.05.2013, 21:03
Написал вот. Работает правильно, но не проверял на контесторах, так что, если найдёте баги пишите.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
#include <deque>
#include <set>
#include <string>
#include <limits>
#include <fstream>
 
using namespace std;
 
vector < vector <double> > inverse(vector < vector <double> > a) {
    int n = a.size();
    vector < vector <double> > ans(n, vector <double> (n, 0));  
    for (int i = 0; i < n; i++){
        ans[i][i] = 1.0;
    }  
    for (int i = 0; i < n; i++){
        int row = i;
        double mx = a[i][i];
        for(int k = i + 1; k < n; k++){
            if (abs(a[k][i]) > mx){
                row = k;
                mx = abs(a[k][i]);
            }
        }
        if (row != i) {
            swap(a[row], a[i]);
            swap(ans[row], ans[i]);
        }
        for (int j = i+1; j < n; j++){
            double e = a[j][i]/a[i][i];
            for (int k = 0; k < n; k++){
                a[j][k] -= e*a[i][k];
                ans[j][k] -= e*ans[i][k];
            }
        }
    }
    for (int i = n - 1; i >= 0; i--) {
        for (int j = i - 1; j >= 0; j--){
            double e = a[j][i]/a[i][i];
            for (int k = 0; k < n; k++){
                a[j][k] -= e*a[i][k];
                ans[j][k] -= e*ans[i][k];
            }
        }
        for (int j = 0; j < n; j++) {
            ans[i][j] /= a[i][i];
        }
    }
    return ans;
}
 
int main(){
    int n;
    cin >> n;
    vector < vector <double> > a(n, vector <double> (n, 0)), ans;
 
    for (int i = 0; i < n; i++){
        for (int j = 0; j < n; j++){
            scanf("%lf", &a[i][j]);
        }
    } 
 
    ans = inverse(a);
 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            printf("%.15lf ", ans[i][j]);
        }
        puts("");
    }
    return 0;
}
Добавлено через 5 минут
Обновил код

Добавлено через 34 минуты
Лично протестировал несколько матриц, всё сходилось. Особенно удобно проверять так : сделали матрицу, нашли обратную, затем нашли обратную к обратной и сверились.
2
0 / 0 / 0
Регистрация: 21.02.2013
Сообщений: 7
23.02.2014, 14:17
извините, если придирчиво проверять(как делает это мой препод по кодингу), ваш код не работает в случае с нулевыми элементами, например для такой матрицы:
0 0 2
0 5 4
6 4 6

Добавлено через 15 минут
Цитата Сообщение от Ternsip Посмотреть сообщение
Лично протестировал несколько матриц, всё сходилось. Особенно удобно проверять так : сделали матрицу, нашли обратную, затем нашли обратную к обратной и сверились.
я пробовал проверять через excel
матрица
0 0 2
0 5 4
6 4 6
первая строка матрицы, найденной юзая ваш код не совпадает
в прочем другие две строки выводятся правильно
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
23.02.2014, 14:51
Цитата Сообщение от Sabijan Посмотреть сообщение
если придирчиво проверять
Это не придирчивость, а вполне обычная проверка стандартной ситуации. У произвольной матрицы на главной диагонали запросто могут быть нулевые элементы. Поэтому правильный метод и включает шаг с перестановкой строк в случае, если очередная строка на главной диагонали содержит нулевой элемент.
1
0 / 0 / 0
Регистрация: 21.02.2013
Сообщений: 7
23.02.2014, 15:11
извините, пытался реализовать ваш код на dev cpp вышла проблема с std::swap. какую библиотеку подключить?

Добавлено через 55 секунд
или можно заменить swap чем-нибудь?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
23.02.2014, 15:11
Помогаю со студенческими работами здесь

Умножить квадратную матрицу на вектор
У кого-нибудь не завалялась функция умножения квадратной матрицы на вектор? Результатом должен быть вектор.

Умножить матрицу 10х10 на вектор из 10 элементов
дана матрица:10*10.умножить ее на вектор 10.помогите пожалуйста...очень нужно

Найти обратную матрицу
Ребят немогу в конда сделал провереку, ошибку выдаёт, не могу найти ошибку помогите!!#include &lt;iostream&gt; #include &lt;cmath&gt; ...

Найти обратную матрицу
Добрый день, уважаемые форумчане! Я знаю, что подобные вопросы получали ответы в разных темах форума, я их подробно перечитала, но решить...

Найти обратную матрицу
Здравствуйте, уважаемые программисты! Прощу помощи. Для заданной матрицы A(3,3), найти обратную А в -1 степени. Нужно ли самому в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru