Je suis en train de faire beaucoup d'arithmétique de matrice et je voudrais profiter de de C99 Je voudrais configurer mes matrices comme des pointeurs sur des pointeurs pour permettre subscripting facile, comme ceci: p> restreindre code> Qualifiant de pointeur.
void mmultiply ( int nrows, int ncols, int **Out, int **A, int **B);
3 Réponses :
L'extérieur (seconde) restreint indique au compilateur qu'aucun des tableaux des pointeurs (A, B et OUT). L'intérieur (premier) restreint indique au compilateur qu'aucun des matrices d'INT (pointé par des éléments des tableaux des pointeurs) alias. P>
Si vous accédez à la fois à un [0] [col * NRows + rangée] et à un [COL] [ligne], alors vous enfreignez la restriction intérieure, les choses peuvent donc casser. P>
Pour la première question, "oui", cela signifiera quelque chose de différent si vous utilisez à la fois des qualificateurs Pour la deuxième question, "oui", il suppose que tout ce qui est accessible via un pointeur de rangée n'est accessible que par le pointeur de la rangée. P>
Vous pouvez lancer Enfin, s'il s'agit de GCC AT -O2, -O3, ou -OS, le compilateur fait déjà une analyse d'alias basée sur des types. Je suis sûr que d'autres compilateurs le font aussi. Cela signifie que restreindre les pointeurs vs L'INT est déjà compris, laissant uniquement les tableaux qui pourraient éventuellement se stocker. p>
En résumé, l'optimiseur supposera que les pointeurs ne sont pas stockés dans l'INT, et il sait que cela ne fait aucun pointeur écrit pendant la boucle. p>
Donc, vous obtiendrez probablement le même code avec seulement celui restreint. P> restreindre code>, en particulier que les pointeurs ne seront pas également aliasés. Quant à savoir si cela fait une différence: théoriquement oui, dans la pratique, cela dépend de l'optimiseur. P>
const code> là aussi. p>
Il faut faire preuve de prudence que la plupart des compilateurs sont beaucoup plus laxistes que GCCX86 sur l'aliasing. MSVC05, par exemple, envisagera même un int * code> et un
float * code> pour éventuellement alias, à moins que vous n'utilisiez restreindre de le dire autrement. (Oui, je sais que ce n'est pas par la spécification, mais le compilateur le fait de toute façon, comme j'ai appris de regarder / Facs.)
@Crashworks: il n'est pas nécessaire dans la spécification, mais une utilisation correcte de restreindre code> peut permettre au code de réaliser essentiellement les mêmes avantages de performance qu'un aliasing strict, mais sans casser aucun code existant, et rien dans la norme interdit aux compilateurs de traiter toutes les opérations comme elles agissent directement sur la mémoire.
Si une fonction prend un pointeur de restriction, et il y a déjà un autre pointeur sur le site d'appel, vous avez maintenant deux pointeurs sur le même objet, qui enfreint la restriction, n'est-ce pas?
si l'identifiant P a type (int
** restreindre), puis les expressions du pointeur P et P + 1 sont basées sur le
objet pointeur restreint désigné
par p, mais les expressions du pointeur * p
et p [1] ne sont pas. P>
blockQuote>
Par analogie avec Je ne sais pas si votre compilateur fera tout ce qui est avec cette connaissance, pensez-vous. Il est clair que cela pourrait, c'est une question de savoir s'il est mis en œuvre. P>
Donc, je ne sais pas vraiment ce que vous avez gagné sur un tableau classique C 2-D, où vous venez d'allouer Au début, la multiplication est susceptible d'être plus rapide qu'une indemnité de pointeur supplémentaire de toute façon. Vous vous souciez évidemment de la performance ou que vous n'utiliseriez pas du tout restreint, donc je testerais des performances assez soigneusement (sur tous les compilateurs que vous vous souciez de) avant de faire ce changement pour le bien plus agréable syntaxe et de ne pas avoir à vous rappeler combien de personnes Colonnes Il y a dans votre tableau à chaque fois que vous y accédez. p>
est d'accéder aux éléments à travers un [0] [col * nrows + rangée] non défini? i> p>
Oui, si l'élément est modifié par l'un des accès, car cela rend un [0] un alias pour la mémoire accessible via un [col]. Ce serait bien si seulement A et B étaient des pointeurs qualifiés restrictifs, mais pas si un [0] et un [col] sont. P>
Je suppose que vous ne modifiez pas A dans cette fonction, alors cet alias va bien. Si vous avez fait la même chose avec le comportement, cela serait indéfini. P> int ** restreindre code> n'affirme que la mémoire adressée à l'extérieur, A et B ne se chevauchent pas (sauf que A et B peuvent se chevaucher, en supposant que votre fonction ne modifie pas l'une ou l'autre d'entre elles) . Cela signifie que les tableaux des pointeurs. Il n'affirme rien sur le contenu de la mémoire pointée à l'extérieur, A et B. Note de bas de page 117 dans N1124 indique: P>
Const code>, je soupçonne que la qualification avec
restreindre code> va-t-elle affirmer ce que vous voulez, qui n'a aucune des valeurs de la matrice ne pointe de la mémoire. Mais en lisant la norme, je ne peux pas me prouver que cela le fait. Je pense que "laissez d une déclaration d'un identifiant ordinaire qui fournit un moyen de désigner un objet P en tant que pointeur qualifié de restriction de type t" signifie effectivement que pour
int * restreindre * restreindre un code> , alors un [0] et A [1] sont des objets désignés comme un pointeur qualifié de restriction sur INT. Mais c'est assez lourd légalois. P>
lignes * cols * Tailleof (int) code> et index avec
Un [cols * rangée + col] code>. Ensuite, vous n'avez clairement besoin que d'une utilisation de restreindre et de tout compilateur qui fait quoi que ce soit avec
restreindre code> sera en mesure de commander des lectures de A et B à travers écrit. Sans
restreindre code>, bien sûr, il ne peut donc pas, alors en faisant ce que vous faites, vous vous jetez sur la miséricorde de votre compilateur. S'il ne peut pas faire face à une double restriction, seul le cas restreint unique, alors votre double indirection vous a coûté l'optimisation. P>
Merci pour la réponse réfléchie. Vous avez raison sur la multiplication étant plus rapide que l'indirection du pointeur; J'avais déjà testé cela pour être généralement vrai. Cependant, je prévois de regrouper les dimensions avec les données dans une structure matricielle pour transmettre. Sans surprise, Déroferience NRows code> à partir du pointeur de structure et multipliant les coûts de la même manière que la déséroférance des pointeurs de données. Dans les fonctions qui y garantissent, je peux la déréférence selon les pointes d'avance et utiliser l'indexation de la matrice 1-D. Et si je le fais de toute façon, je peux aussi bien fournir la syntaxe plus belle [col] [ligne] ailleurs.
Un grand gros "merci" à tous les répondeurs! C'est une honte que je ne puisse choisir qu'une réponse "correcte" - vous avez tous aidé à réfléchir à des problèmes impliqués.
Onze ans plus tard et j'aimerais revenir à temps pour crier à mon ancien moi-même pour ne pas utiliser de blas . Ok, d'accord, openblas n'a pas existé à l'époque, mais L'ancien NetLib Blas a fait. Dans tous les cas, optimiser les multiplications matricielles n'est pas le genre de chose que vous voulez vous retrouver faire sur un caprice!