Pregunta

Estoy haciendo un montón de aritmética matriz y me gustaría aprovechar calificador puntero restrict de C99.

Me gustaría configurar mi matrices como punteros a punteros para permitir una fácil subíndices, así:

int **A = malloc (ncols * sizeof(int *));
A[0] = malloc (nrows * ncols * sizof(int));
for (int i=1; i < ncols; i++) {
    A[i] = A[0] + i*nrows;
}

Ahora, para una función de multiplicación de matrices

void mmultiply ( int nrows, int ncols, int **Out, int **A, int **B);

he de calificar los dos punteros de los argumentos como restringida? Es una sintaxis válida, pero estoy teniendo dificultades para determinar si int *restrict *restrict se comporta de forma diferente a int **restrict.

A continuación, con los punteros adecuadamente restringidos, está accediendo a través de elementos de A[0][col*nrows + row] indefinido? (Es decir, será el compilador suponer que I solamente acceder a la matriz a través A[col][row] para valores de row tales que row < nrow)? O debo simplemente seguir siendo coherente?

¿Fue útil?

Solución

Para la primera pregunta, "sí", significará algo diferente, si se utilizan los dos calificadores restrict, en concreto, que los punteros tampoco serán alias. En cuanto a si se hace alguna diferencia: en teoría sí, en la práctica, que depende del optimizador

.

Para la segunda pregunta, "sí", se asumirá que cualquier cosa que se accede a través de un puntero de fila está a sólo accede a través del puntero de fila.

Se podría lanzar const allí también.

Por último, si esto es gcc en O2, O3, o -Os, el compilador lo está haciendo ya un análisis de alias basado en tipos. Estoy seguro de que otros compiladores hacen esto también. Esto significa que la restricción de los punteros vs los enteros ya se entiende, dejando sólo las matrices que podría almacenar el uno al otro.

En suma, el optimizador asumirá que los punteros no están siendo almacenados en como enteros, y se sabe que no está haciendo ningún puntero escribe durante el bucle.

Así que es probable que obtener el mismo código con sólo el uno restringir.

Otros consejos

El exterior (segundo) restringir le dice al compilador que ninguno de los arreglos de apuntadores (A, B, y por fuera) alias. El interior (primero) restringir indica al compilador que ninguno de los arrays de enteros (a la que apunta elementos de las matrices de punteros) alias.

Si tiene acceso tanto a [0] [col * + nfilas fila] y A [col] [fila] entonces usted está violando restringen el interior, así que las cosas podrían romperse.

int **restrict sólo se afirma que la memoria direccionada por fuera, A y B no se solapan (excepto que A y B se pueden superponer, asumiendo que su función no modifica ninguno de los dos). Esto significa que los arreglos de apuntadores. No afirma nada sobre el contenido de la memoria a la que apunta hacia fuera, A y B. Nota al pie 117 en n1124 dice:

  

si identificador p tiene tipo (int   ** restringir), entonces el puntero expresiones py p + 1 se basan en el   restringido objeto de puntero designado   por P, pero las expresiones puntero p *   y p [1] no son.

Por analogía con const, sospecho que la calificación con restrict hará valer el doble de lo que quiere, que es que ninguno de los valores en la matriz apunta a la memoria superpuestas. Pero la lectura de la norma, no puedo demostrar a mí mismo que lo que realmente hace. Calculo que "Sea D una declaración de un identificador común que proporciona un medio de designación de un objeto P como un puntero restringir cualificado para escribir T" en efecto significa que para int *restrict *restrict A, entonces A [0] y A [1] son objetos designados como puntero restringir-calificado para int. Pero es bastante pesado jerga legal.

No tengo ni idea de si su compilador realmente hacer algo con ese conocimiento, que conste. Está claro que podía, que es una cuestión de si se implementa.

Así que no se sabe muy bien lo que has ganado a través de una variedad convencional C 2-D, donde se acaba de asignar rows * cols * sizeof(int), y el índice con A[cols*row + col]. A continuación, sólo necesita una clara utilización de restringir, y cualquier compilador que hace algo con restrict será capaz de volver a pedir lee de A y B, escribe a través de fuera. Sin restrict, por supuesto, no puede, por lo que al hacer lo que estás haciendo, estás tirando a sí mismo en la misericordia de su compilador. Si no se puede hacer frente a la doble restringir, sólo el único caso restringir, entonces su doble indirección que ha costado a la optimización.

En primera aproximación, la multiplicación es probable que sea más rápido que una indirección de puntero adicional de todos modos. Es obvio que se preocupan por el rendimiento o que no estaría utilizando restringir en absoluto, así que me gustaría probar el rendimiento bastante cuidado (en todos los compiladores se preocupan por) antes de hacer este cambio por el bien de la sintaxis un poco más bonitas y no tener que recordar cuántas columnas que hay en su conjunto cada vez que acceda a él.

está accediendo a los elementos a través de una [0] [col * nRows + fila] indefinido?

Sí, si el elemento es modificado por uno de los accesos, porque esto hace que A [0] un alias para la memoria también accede a través de A [col]. Eso estaría bien si solamente A y B fueron punteros restringir cualificados, pero no si A [0] y A [col] son.

Asumo que no modifique A en esta función, por lo que en realidad ese alias está muy bien. Si usted hizo lo mismo con el de salida, sin embargo, el comportamiento sería indefinido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top