una resto residuo operadores operador logicos lenguaje escribir entera como calcular c performance x86 floating-point stencils

resto - operadores logicos en lenguaje c



Multiplicación flotante realizando más lento dependiendo de los operandos en C (2)

Estoy realizando un cálculo de plantilla en una matriz que leí previamente de un archivo. Yo uso dos tipos diferentes de matrices (tipo no cero y tipo cero). Ambos tipos comparten el valor de los límites (1000 generalmente), mientras que el resto de los elementos son 0 para el tipo Cero y 1 para el tipo No Cero.

El código almacena la matriz del archivo en dos matrices asignadas del mismo tamaño. Luego realiza una operación en cada elemento de una matriz utilizando su propio valor y valores de vecinos (sume x 4 y mul x 1), y almacena el resultado en la segunda matriz. Una vez finalizado el cálculo, se intercambian los punteros de las matrices y se realiza la misma operación por un tiempo finito. Aquí tienes el código central:

#define GET(I,J) rMat[(I)*cols + (J)] #define PUT(I,J) wMat[(I)*cols + (J)] for (cur_time=0; cur_time<timeSteps; cur_time++) { for (i=1; i<rows-1; i++) { for (j=1; j<cols-1; j++) { PUT(i,j) = 0.2f*(GET(i-1,j) + GET(i,j-1) + GET(i,j) + GET(i,j+1) + GET(i+1,j)); } } // Change pointers for next iteration auxP = wMat; wMat = rMat; rMat = auxP; }

El caso en el que estoy exponiendo utiliza una cantidad fija de 500 timeSteps (iteraciones externas) y un tamaño de matriz de 8192 filas y 8192 columnas, pero el problema persiste al cambiar el número de timeSteps o del tamaño de la matriz. Tenga en cuenta que solo mido el tiempo de esta parte concreta del algoritmo, por lo que la lectura de la matriz del archivo ni ninguna otra cosa afecta la medida del tiempo.

Lo que sucede es que obtengo diferentes tiempos dependiendo del tipo de matriz que uso, obteniendo un rendimiento mucho peor cuando uso el tipo Cero (todas las demás matrices funcionan igual que las del tipo No Cero, ya que he intentado generar una matriz llena de datos aleatorios). valores).

Estoy seguro de que es la operación de multiplicación, ya que si la quito y solo dejo los agregados, se realizan de la misma manera. Tenga en cuenta que con el tipo de matriz Cero, la mayoría del tipo de resultado de la suma será 0, por lo que la operación será "0.2 * 0".

Este comportamiento es ciertamente extraño para mí, ya que pensé que las operaciones de punto flotante eran independientes de los valores de los operandos, lo que no parece ser el caso aquí. También traté de capturar y mostrar excepciones SIGFPE en caso de que ese fuera el problema, pero no obtuve resultados.

En caso de que ayude, estoy usando un procesador Intel Nehalem y gcc 4.4.3.


El problema ya ha sido diagnosticado en su mayoría, pero voy a escribir exactamente lo que sucede aquí.

Esencialmente, el que pregunta está modelando la difusión; una cantidad inicial en el límite se difunde en la totalidad de una cuadrícula grande. En cada paso de tiempo t, el valor en el borde anterior de la difusión será 0.2 ^ t (ignorando los efectos en las esquinas).

El valor de precisión simple normalizado más pequeño es 2 ^ -126; cuando cur_time = 55 , el valor en la frontera de la difusión es 0.2 ^ 55, que es un poco más pequeño que 2 ^ -127. A partir de este momento, algunas de las celdas de la cuadrícula contendrán valores denormales . En el Nehalem del interrogador, las operaciones en datos desnormales son aproximadamente 100 veces más lentas que la misma operación en datos de punto flotante normalizados, lo que explica la desaceleración.

Cuando la cuadrícula se llena inicialmente con datos constantes de 1.0 , los datos nunca se vuelven demasiado pequeños, por lo que se evita el bloqueo denormal.

Tenga en cuenta que cambiar el tipo de datos al double retrasaría, pero no aliviaría el problema. Si se utiliza la precisión doble para el cálculo, los valores denormales (ahora más pequeños que 2 ^ -1022) surgirán primero en la 441a iteración.

Al costo de la precisión en el borde inicial de la difusión, puede corregir la desaceleración al habilitar "Flush to Zero", lo que hace que el procesador produzca cero en lugar de resultados denormales en operaciones aritméticas. Esto se hace alternando un poco en el FPSCR o MXSCR, preferiblemente a través de las funciones definidas en el <fenv.h> en la biblioteca C.

Otro "arreglo" (más intrépido, menos bueno) sería llenar la matriz inicialmente con valores no cero muy pequeños ( 0x1.0p-126f , el número normal más pequeño). Esto también evitaría que surjan denormales en el cálculo.


Tal vez su ZeroMatrix usa el esquema de almacenamiento típico para matrices dispersas: almacene todos los valores que no sean cero en una lista vinculada. Si ese es el caso, es bastante comprensible por qué se comporta peor que un esquema de almacenamiento basado en arreglos típico: porque debe ejecutarse en la lista vinculada una vez por cada operación que realice. En ese caso, tal vez pueda acelerar el proceso utilizando un algoritmo de multiplicación de matrices que tenga una matriz dispersa. Si este no es el caso, publique un código mínimo pero completo para que podamos jugar con él.

Esta es una de las posibilidades para multiplicar matrices dispersas de manera eficiente:

http://www.cs.cmu.edu/~scandal/cacm/node9.html