Pergunta

Estou fazendo muita aritmética matriz e gostaria de aproveitar qualificador ponteiro restrict de C99.

Eu gostaria de configurar meus matrizes como ponteiros para ponteiros para permitir a fácil subscripting, assim:

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;
}

Agora, para uma função multiplicação de matrizes

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

I deve qualificar ambos os ponteiros dos argumentos tão restrito? É sintaxe válida, mas eu estou tendo um momento difícil determinar se comporta int *restrict *restrict de forma diferente do int **restrict.

Em seguida, com os ponteiros corretamente restrito, está acessando elementos através A[0][col*nrows + row] indefinido? (Ou seja, vai o compilador assumir que eu única acesso a matriz através A[col][row] para valores de row tal que row < nrow)? Ou devo simplesmente manter a coerência?

Foi útil?

Solução

Para a primeira pergunta, "sim", isso significará algo diferente se você usar os dois qualificadores restrict, especificamente, que os ponteiros também não vai ser alias. Quanto a saber se ele faz alguma diferença: teoricamente sim, na prática, isso depende do otimizador

.

Para a segunda pergunta, "sim", ele assumirá que nada acessado através de um ponteiro de linha só é acessado através o ponteiro de linha.

Você poderia jogar const lá também.

Finalmente, se este é gcc em -O2, O3, ou -Os, o compilador já está fazendo uma análise apelido baseado em tipos. Eu tenho certeza que outros compiladores fazer isso também. Isto significa que restringir os ponteiros vs os ints já é compreendido, deixando apenas as matrizes que poderia armazenar um ao outro.

Em suma, o otimizador irá assumir que os ponteiros não estão sendo armazenados em como ints, e ele sabe que não está fazendo nenhum escreve ponteiro durante o loop.

Então, você provavelmente terá o mesmo código com apenas o restringir.

Outras dicas

O exterior (segundo) restringir informa o compilador que nenhuma das matrizes de ponteiros (A, B, e para fora) alias. O interior (primeiro) restringir informa o compilador que nenhum dos conjuntos de ints (apontada por elementos das matrizes de ponteiros) alias.

Se você acessar ambos A [0] [col * nrows + linha] e A [col] [linha], então você está violando restringir o interior, então as coisas podem quebrar.

int **restrict única afirma que a memória endereçada por Fora, A e B não se sobrepõem (exceto que A e B podem sobrepor-se, assumindo a sua função não modifica nenhum dos dois). Isso significa que as matrizes de ponteiros. Ele não afirma nada sobre o conteúdo da memória apontada por Fora, A e B. Nota de rodapé 117 em n1124 diz:

Se identificador p tem o tipo (int ** restringir), então o ponteiro expressões p e p + 1 baseiam-se na objeto ponteiro restrito designado por p, mas as expressões ponteiro * P e p [1] não são.

Por analogia com const, eu suspeito que a qualificação com restrict duas vezes fará valer o que você quer, o que é que nenhum dos valores nos pontos de matriz de sobreposição de memória. Mas lendo o padrão, eu não posso provar a mim mesmo que ele realmente faz. Calculo que "Seja D uma declaração de um identificador comum que proporciona um meio de designando um objecto P como um ponteiro restringir-qualificado para tipo T", de facto, significa que para int *restrict *restrict A, então A [0] e [1] são objetos designado como um ponteiro restringir-qualificado para int. Mas é juridiquês muito pesado.

Eu não tenho idéia se o seu compilador irá realmente fazer alguma coisa com esse conhecimento, você mente. Claramente o que podia, é uma questão de saber se ele é implementado.

Então, eu realmente não sei o que você ganhou ao longo de um convencional C matriz de 2-D, onde você só alocar rows * cols * sizeof(int) e índice com A[cols*row + col]. Então você claramente só precisa de um uso de restringir, e qualquer compilador que faz qualquer coisa com restrict será capaz de re-encomenda lê A e B através de gravações para fora. Sem restrict, é claro, não pode, por isso, fazer o que você está fazendo, você está jogando-se sobre a misericórdia de seu compilador. Se ele não consegue lidar com duplo restringir, apenas o único restringir caso, então o seu duplo engano custou-lhe a otimização.

Na primeira suposição, a multiplicação é provável que seja mais rápido do que um engano ponteiro adicional de qualquer maneira. Você, obviamente, se preocupam com o desempenho ou você não estaria usando restringir em tudo, então eu testar o desempenho bastante cuidado (em todos os compiladores você se preocupa) antes de fazer esta mudança para o bem de um pouco mais agradável sintaxe e não ter que lembrar de quantas colunas existem em sua matriz cada vez que você acessá-lo.

está acessando elementos através de A [0] [col * nrows + row] indefinido?

Sim, se o elemento é modificado por um dos acessos, porque isso faz com que A [0] um alias para memória também acessado através de um [col]. Isso seria bom se apenas A e B foram ponteiros restringir-qualificados, mas não se A [0] e A [col] são.

Eu suponho que você não modifique A nesta função, por isso, na verdade, que alias é bem. Se você fez a mesma coisa com o Fora, porém, o comportamento seria indefinida.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top