Để giải quyết bài toán, chúng ta có thể sử dụng mô hình đồng bộ hóa dữ liệu (data parallelism) trong lập trình song song. Ta có thể sử dụng OpenMP để tạo ra các tiểu trình để tính toán một phần tử của ma trận kết quả.
Đầu tiên, ta cần định nghĩa số hàng và số cột của ma trận kết quả. Sau đó, ta sẽ đọc vào ma trận A và ma trận B từ tệp dữ liệu data.dat.
Tiếp theo, ta sử dụng các vòng lặp để tạo ra M * N tiểu trình để tính toán một phần tử của ma trận kết quả. Mỗi tiểu trình sẽ tính toán một phần tử của ma trận kết quả theo công thức đã cho và lưu vào một mảng.
Cuối cùng, tuyến chính sẽ đợi tất cả các tiểu trình tính toán xong, sau đó in ra ma trận kết quả.
Dưới đây là mã nguồn cho bài toán trên:
C#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int main()
{
int M, K, N, i, j, n;
double sum;
// Đọc vào số hàng, số cột của ma trận A và ma trận B
FILE *fp = fopen("data.dat", "r");
fscanf(fp, "%d %d %d", &M, &K, &N);
// Tạo ma trận A và đọc vào từ tệp dữ liệu
double **A = (double **)malloc(M * sizeof(double *));
for (i = 0; i < M; i++)
A[i] = (double *)malloc(K * sizeof(double));
for (i = 0; i < M; i++)
for (j = 0; j < K; j++)
fscanf(fp, "%lf", &A[i][j]);
// Tạo ma trận B và đọc vào từ tệp dữ liệu
double **B = (double **)malloc(K * sizeof(double *));
for (i = 0; i < K; i++)
B[i] = (double *)malloc(N * sizeof(double));
for (i = 0; i < K; i++)
for (j = 0; j < N; j++)
fscanf(fp, "%lf", &B[i][j]);
// Tạo ma trận C và tính toán giá trị của từng phần tử
double **C = (double **)malloc(M * sizeof(double *));
for (i = 0; i < M; i++)
C[i] = (double *)malloc(N * sizeof(double));
#pragma omp parallel for private(j, n, sum)
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
sum = 0.0;
for (n = 0; n < K; n++)
sum += A[i][n] * B[n][
Đây là phần tiếp theo của code:
css int main()
{
// Đọc file và lưu ma trận A và B vào các mảng
FILE* fp;
fp = fopen("data.dat", "r");
int M, K, N;
fscanf(fp, "%d %d %d", &M, &K, &N);
int A[M][K], B[K][N];
for (int i = 0; i < M; i++) {
for (int j = 0; j < K; j++) {
fscanf(fp, "%d", &A[i][j]);
}
}
for (int i = 0; i < K; i++) {
for (int j = 0; j < N; j++) {
fscanf(fp, "%d", &B[i][j]);
}
}
fclose(fp);
// Tạo các tuyến con để tính toán phần tử Ci,j của ma trận kết quả
#pragma omp parallel num_threads(M*N)
{
int tid = omp_get_thread_num();
int i = tid / N;
int j = tid % N;
int sum = 0;
for (int n = 0; n < K; n++) {
sum += A[i][n] * B[n][j];
}
#pragma omp critical
{
C[i][j] = sum;
}
}
// In ra ma trận kết quả C
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
printf("%d ", C[i][j]);
}
printf("\n");
}
return 0;
}
Trong hàm main
, đầu tiên chúng ta đọc file data.dat
và lưu ma trận A và B vào các mảng A
và B
tương ứng. Sau đó, chúng ta tạo các tuyến con để tính toán phần tử Ci,j của ma trận kết quả. Mỗi tuyến con tính toán một phần tử và lưu vào mảng C
. Ở đây, chúng ta sử dụng num_threads(M*N)
để tạo ra M*N tuyến con, và sử dụng hàm omp_get_thread_num()
để lấy ra ID của tuyến con hiện tại. Tiếp theo, chúng ta tính toán phần tử C[i][j] của ma trận kết quả bằng cách sử dụng công thức đã cho. Cuối cùng, chúng ta sử dụng #pragma omp critical
để đảm bảo rằng chỉ có một tuyến con được phép thực hiện lệnh ghi vào mảng C
một lúc.
Sau khi tất cả các tuyến con đã tính toán xong, chúng ta in ra ma trận kết quả C bằng cách duyệt qua mảng C
và in từng phần tử ra màn hình.