Sobre una matriz de números enteros, A de dimensión NxN, se realizan varias iteraciones actualizando cada elemento con la media de ese elemento con los vecinos. En las iteraciones pares se consideran sus vecinos en vertical y horizontal, y en las impares en diagonal. Por simplificar se considera que se hace siempre la media de cinco elementos.
Se resuelven varios problemas. Para cada problema la función a paralelizar tiene parámetros:
Input parameters:
-int N: número de filas y columnas
Input/Output parameter:
-int *A: matriz de dimensión NxN
La entrada tiene en la primera línea el número de problemas. Para cada problema hay una línea con seis valores: N, el número de iteraciones, la semilla para la generación aleatoria, los valores mínimo y máximo para la generación, y un valor que indica cada cuantos elementos se escribe uno a la salida.
3 10 4 1 -20 20 1 12000 18 2 -250 250 1370 12300 17 3 -200 200 2107
/* CPP_CONTEST=2018Enero CPP_PROBLEM=A CPP_LANG=CPP+OPENMP CPP_PROCESSES_PER_NODE=jupiter 1 */ #include < stdlib.h > #include < omp.h > extern void escribir(int *,int,int); void filapar(int n,int *A,int *B) { B[0]=(A[-n]+A[0]+A[1]+A[n])/5; //casilla izquierda for(int i=1;i < n-1;i++) //casillas no extremas de la fila B[i]=(A[i-n]+A[i-1]+A[i]+A[i+1]+A[i+n])/5; B[n-1]=(A[-1]+A[n-2]+A[n-1]+A[2*n-1])/5; //casilla derecha } void filaimpar(int n,int *A,int *B) { B[0]=(A[-n+1]+A[0]+A[n+1])/5; //casilla izquierda for(int i=1;i < n-1;i++) //casillas no extremas de la fila B[i]=(A[i-n-1]+A[i-n+1]+A[i]+A[i+n-1]+A[i+n+1])/5; B[n-1]=(A[-2]+A[n-1]+A[2*n-2])/5; //casilla derecha } void par(int n,int *A,int *B) { B[0]=(A[0]+A[1]+A[n])/5; //casilla superior-izquierda for(int i=1;i < n-1;i++) //casillas no extremas de la primera fila B[i]=(A[i-1]+A[i]+A[i+1]+A[i+n])/5; B[n-1]=(A[n-2]+A[n-1]+A[2*n-1])/5; //casilla superior-derecha for(int i=1;i < n-1;i++) //para el resto de filas menos la última filapar(n,&A[i*n],&B[i*n]); B[(n-1)*n]=(A[(n-1)*n-n]+A[(n-1)*n]+A[(n-1)*n+1])/5; //casilla inferior-izquierda for(int i=1;i < n-1;i++) //casillas no extremas de la última fila B[(n-1)*n+i]=(A[(n-1)*n+i-n]+A[(n-1)*n+i-1]+A[(n-1)*n+i]+A[(n-1)*n+i+1])/5; B[(n-1)*n+n-1]=(A[(n-1)*n-1]+A[(n-1)*n+n-2]+A[(n-1)*n+n-1])/5; //casilla inferior-derecha } void impar(int n,int *A,int *B) { B[0]=(A[0]+A[n+1])/5; //casilla superior-izquierda for(int i=1;i < n-1;i++) //casillas no extremas de la primera fila B[i]=(A[n+i-1]+A[i]+A[n+i+1])/5; B[n-1]=(A[2*n-2]+A[n-1])/5; //casilla superior-derecha for(int i=1;i < n-1;i++) //para el resto de filas menos la última filaimpar(n,&A[i*n],&B[i*n]); B[(n-1)*n]=(A[(n-1)*n]+A[(n-1)*n-n+1])/5; //casilla inferior-izquierda for(int i=1;i < n-1;i++) //casillas no extremas de la última fila B[(n-1)*n+i]=(A[(n-1)*n+i-n-1]+A[(n-1)*n+i]+A[(n-1)*n+i-n+1])/5; B[(n-1)*n+n-1]=(A[(n-1)*n-2]+A[(n-1)*n+n-1])/5; //casilla inferior-derecha } void copiar(int *vo,int n,int *vd) { for(int i=0;i < n;i++) vd[i]=vo[i]; } void sec(int n,int *A,int numiter) { int *B=new int[n*n]; int numiter2=numiter/2; for (int i = 0; i < numiter2; i++) { par(n,A,B); #ifdef DEBUG escribir(B,n,n); #endif impar(n,B,A); #ifdef DEBUG escribir(A,n,n); #endif } if(numiter2*2!=numiter) { par(n,A,B); #ifdef DEBUG escribir(B,n,n); #endif copiar(B,n*n,A); } #ifdef DEBUG escribir(A,n,n); #endif delete[] B; }
esquema-openmp.cpp (no modificable, lo usa mooshak para entrada/salida y evaluación, se proporciona para experimentación en local)
#include < stdlib.h > #include < stdio.h > #include < sys/time.h > #include < omp.h > #include < signal.h > #include < unistd.h > //Prueba de Metodología de la Programación Paralela //enero 2018 //Iteración de Jacobi vertical / diagonal, versión OpenMP //Esquema para entrada/salida, validación y toma de tiempos void generar(int *m, int t,int lv,int uv) { int i; for (i = 0; i < t; i++) { m[i] =(int) (((1. * rand()) / RAND_MAX)*(uv-lv)+lv); } } void escribir(int *m, int N,int M) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < M; j++) printf("%d ", m[i * M + j]); printf("\n"); } printf("\n"); } void escribirresult(int *a,int N,int salida) { int i; for(i=0;i < N;i++) { if((i%salida)==0) { printf("%d \n",a[i]); } } printf("\n"); } /* c c mseconds - returns elapsed milliseconds since Jan 1st, 1970. c */ long long mseconds(){ struct timeval t; gettimeofday(&t, NULL); return t.tv_sec*1000 + t.tv_usec/1000; } static void alarm_handler(int sig) { fprintf(stderr, "Time Limit Exceeded\n"); abort(); } extern void sec(int n,int *A,int numiter); int main(int argc,char *argv[]) { int N; //tamaño matriz int *A; int cuantos; //número de problemas int numiter; //número de iteraciones int semilla; //semilla para generación aleatoria int lv,uv; //valores inferior y superior para generación aleatoria int salida; //indica cada cuantos elementos se escribe uno a la salida long long ti,tf,tt=0; FILE *stats_file = fopen("stats", "w"); struct sigaction sact; sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sact.sa_handler = alarm_handler; sigaction(SIGALRM, &sact, NULL); alarm(60); /* time limit */ scanf("%d",&cuantos); for(int i=0;i < cuantos;i++) { scanf("%d",&N); scanf("%d",&numiter); scanf("%d",&semilla); scanf("%d",&lv); scanf("%d",&uv); scanf("%d",&salida); A = (int *) calloc(sizeof(int),N*N); srand(semilla); generar(A,N*N,lv,uv); #ifdef DEBUG escribir(A,N,N); #endif ti=mseconds(); sec(N,A,numiter); tf=mseconds(); #ifdef DEBUG escribir(A,N,N); #endif if(i!=0) tt+=tf-ti; escribirresult(A,N*N,salida); free(A); } fprintf(stats_file, "%Ld\n", tt); fclose(stats_file); return 0; }