USER
逆行列の算出ですが、20000x20000 だと、倍精度が必要なようです。
11:53:46 2025 Matrix 20000x 20000
Generate an array of random numbers
Elapsed time: 0h 0m 4s 311ms 888us
11:53:50
Inverse matrix size: 20000 X 20000
Elapsed time: 4h 7m 17s 946ms 212us
16:01:12
Generated matrix X Inverse matrix size: 20000 X 20000
Elapsed time: 2h 43m 33s 310ms 82us
18:44:48
E is an identity matrix
18:44:48
AI
USER
LU分解でも long double が必要ということです。
AI
USER
ただ、PC で 20000×20000 が半日もかからず解けるのは驚きでもあります。
AI
USER
BLAS を使って 20000×20000 の行列の逆行列 を解くと何秒ぐらいで解けますか?
AI
USER
// 動的メモリ確保
A = (double **)alloc2Darray(sizeof(double), n, n);
A_inv = (double **)alloc2Darray(sizeof(double), n, n);
E = (double **)alloc2Darray(sizeof(double), n, n);
double start_time, end_time, date_Begin, date_i, date_e, date_v, date;
date_Begin = date = *localtime(&timer);
// ランダムな値で初期化されたnxn行列
start_time = get_micro_time();
for(int i=0; i<n; i++)for(int j=0; j<n; j++) A[i][j]=100.*(double)rand()/RAND_MAX;
end_time = get_micro_time();
time(&timer); date_o = date = *localtime(&timer);
////////////////////////////////////////////////////////////////////////////////////////////////
// 逆行列を計算
start_time = get_micro_time();
inverse_matrix_wrapping( A, A_inv, n );
end_time = get_micro_time();
time(&timer); date_i = date = *localtime(&timer);
////////////////////////////////////////////////////////////////////////////////////////////////
start_time = get_micro_time();
multiplication_matrixEx(A, A_inv, E, n);
end_time = get_micro_time();
time(&timer); date_e = date = *localtime(&timer);
////////////////////////////////////////////////////////////////////////////////////////////////
fflush(stdout); if(ofname && fp)fflush(fp);
long long flag=0;
for(int y=0; y<n; y++)for(int x=0; x<n; x++){
int v = 100000*(E[y][x]+ 0.0000001);
if( y==x ){if(v!=100000){if(perr)printf("ERROR: (% 6d,% 6d) %d\n", x, y, v); flag++; }
} else if( v ){ flag++; if(perr)printf("ERROR: (% 6d,% 6d) %d\n", x, y, v); }
}
time(&timer); date_v = *localtime(&timer);
////////////////////////////////////////////////////////////////////////////////////////////////
printf((flag?"\nE is not an identity matrix. %lld\n":"\nE is an identity matrix\n"),flag);
void inverse_matrix_DoublePrecision(double** A, double** A_inv, int n) {
long double** L = (long double**)malloc(n * sizeof(long double*));
long double** U = (long double**)malloc(n * sizeof(long double*));
long long* P = (long long*)malloc(n * sizeof(long long));
if( L && U && P ){
for(int i=0; i<n; i++) {
L[i] = (long double*)calloc(n, sizeof(long double));
U[i] = (long double*)calloc(n, sizeof(long double));
if( !L[i] && !U[i] ){
perror("Memory allocation error L[i],U[i] in inverse_matrix\n");
exit(1);
}
}
lu_decomposition_DoublePrecision(A, L, U, P, n);
#pragma omp parallel for schedule(dynamic)
for(int i=0; i<n; i++) {
long double* e = (long double*)calloc(n, sizeof(long double));
long double* x = (long double*)calloc(n, sizeof(long double));
if( e && x ){
e[i] = 1.0;
solve_LU_DoublePrecision(L, U, P, e, x, n);
for(int j=0; j<n; j++) A_inv[j][i] = x[j];
} else { perror("Memory allocation error for solve_LU_DoublePrecision\n"); exit(1); }
free(e);
free(x);
}
} else { perror("Memory allocation error in inverse_matrix\n"); exit(1); }
for(int i=0; i<n; i++){ free(L[i]); free(U[i]); }
free(L); free(U); free(P);
}
AI
USER
////////////////////////////////////////////////////////////////////////////////////////////////
fflush(stdout); if(ofname && fp)fflush(fp);
long long flag=0;
for(int y=0; y<n; y++)for(int x=0; x<n; x++){
int v = 100000*(E[y][x]+ 0.0000001);
if( y==x ){if(v!=100000){if(perr)printf("ERROR: (% 6d,% 6d) %d\n", x, y, v); flag++; }
} else if( v ){ flag++; if(perr)printf("ERROR: (% 6d,% 6d) %d\n", x, y, v); }
}
time(&timer); date_v = *localtime(&timer);
////////////////////////////////////////////////////////////////////////////////////////////////
printf((flag?"\nE is not an identity matrix. %lld\n":"\nE is an identity matrix\n"),flag);
AI
USER
プラスに振れます。 マイナス0を消すのが目的で、100000 して整数にするので、さらにその1/10は無視できる値ということです
AI