Матрица с плавающей точкой перестает меняться после нескольких умножений

0

У меня есть double a[50][50]; 2D-массив, который я инициализирую с помощью значений с плавающей запятой меньше 1. После умножения матрицы 14-15 раз на себя, матрица остается неизменной.

Чтобы быть более конкретным, я обнаружил A^k где A - двумерная матрица. Значения матрицы перестают меняться после 14 умножений.

Как я могу предотвратить это? Я хочу выполнить матричные умножения при больших значениях k,

1 <= k <= 10^9.

#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
#define ll long long
#define pb push_back
using namespace std;

std::vector<std::vector<double> > A(51, std::vector<double>(51));
void expo(long long t,int n){
    if(t==1)
        return;
    std::vector<std::vector<double> > B(n+1, std::vector<double>(n+1));
    if(t&1){
        for(int x=0;x<n;x++)
            for(int y=0;y<n;y++)
                B[x][y]=A[x][y];
    }
    std::vector<std::vector<double> > C(n+1, std::vector<double>(n+1));
    for(int x=0;x<n;x++)
        for(int y=0;y<n;y++){
            C[x][y]=0;
            for(int z=0;z<n;z++){
                C[x][y]=(C[x][y]+A[x][z]*A[z][y]);
            }
        }
    for(int x=0;x<n;x++)
        for(int y=0;y<n;y++)
            A[x][y]=C[x][y];
    expo(t>>1,n);
    if(t&1){
        for(int x=0;x<n;x++)
            for(int y=0;y<n;y++){
                C[x][y]=0;
                for(int z=0;z<n;z++){
                    C[x][y]=(C[x][y]+A[x][z]*B[z][y]);
                }
            }
        for(int x=0;x<n;x++)
            for(int y=0;y<n;y++)
                A[x][y]=C[x][y];
    }
}
int main(){
    int k;
    cin>>k;
    int ix,iy;
    for(ix=0;ix<50;ix++)
        for(iy=0;iy<50;iy++)
            cin>>A[ix][iy];

    expo(k,50);
    for(int i=0;i<50;i++) 
    {
        for(int j=0;j<50;j++) 
        {
            cout<<A[i][j]<<" ";
        }
        cout<<"\n";
    }

    return 0;
}

РЕДАКТИРОВАТЬ:

  1. Данная матрица является марковской матрицей.

  2. Я заменил double a[50][50]; с std::vector<std::vector<double> > a(50, std::vector<double>(50)); (размер вектора может варьироваться)

  • 0
    double B[n+1][n+1]; Это не разрешено C ++. Размеры массивов должны быть известны во время компиляции.
  • 0
    Я не смотрел на ваш код, чтобы проверить его, но если предполагается, что матрица представляет матрицу Маркова, то достаточно часто, A^k->A особенно если вы используете конечные числа с плавающей запятой для ее представления.
Показать ещё 4 комментария
Теги:
floating-point
matrix-multiplication
pow

1 ответ

1
Лучший ответ

Я верну свои комментарии в ответ:

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

Изображение 174551

После n итераций получаем, что

Изображение 174551

Таким образом, любое начальное состояние (сумма элементов должно равняться 1) приведет к {2/3, 1/3}. При использовании чисел с плавающей запятой для представления значений матрицы изменение между итерацией n и n+1 часто может быть меньше, чем ULP.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню