Le compilateur ne peut pas généralement transformer
for (int c = 0; c < arraySize; ++c)
if (data[c] >= 128)
for (int i = 0; i < 100000; ++i)
sum += data[c];
en
for (int c = 0; c < arraySize; ++c)
if (data[c] >= 128)
sum += 100000 * data[c];
parce que cette dernière pourrait conduire à un débordement d'entiers signés, où l'ancienne qui ne fonctionne pas. Même avec des garanties de wrap-around comportement pour le débordement de l'signé en complément à deux entiers, il serait de changer le résultat (si data[c]
est 30000, le produit deviendra -1294967296
pour le type 32 bits int
s avec une pellicule autour, alors que 100000 fois l'ajout de 30000 à sum
serait, si ce n'est pas de débordement, d'accroître sum
par 3000000000). Notez que l'en est de même pour les quantités, avec des numéros différents, le débordement d' 100000 * data[c]
généralement introduire une réduction modulo 2^32
qui ne doivent pas apparaître dans le résultat final.
Il pouvait se transformer en
for (int c = 0; c < arraySize; ++c)
if (data[c] >= 128)
sum += 100000LL * data[c]; // resp. 100000ull
si, si, comme d'habitude, long long
est suffisamment plus grand que int
.
Pourquoi il ne le fait pas, je ne peux pas dire, je suppose que c'est ce que Mysticial dit, "apparemment, il n'a pas d'exécuter une boucle-effondrement passe après la boucle-échange".
Notez que la boucle de l'échangeur lui-même n'est généralement pas valide (pour les entiers signés), depuis
for (int c = 0; c < arraySize; ++c)
if (condition(data[c]))
for (int i = 0; i < 100000; ++i)
sum += data[c];
peut conduire à débordement où
for (int i = 0; i < 100000; ++i)
for (int c = 0; c < arraySize; ++c)
if (condition(data[c]))
sum += data[c];
ne le soit pas. C'est casher ici, depuis que l'état garantit à tous data[c]
qui sont ajoutés ont le même signe, donc si on déborde, tous les deux.
Je ne serais pas trop sûr que le compilateur a pris cela en compte, si (@Mysticial, pourriez-vous essayer avec un état comme la data[c] & 0x80
ou de sorte que peut-être vrai pour les valeurs positives et négatives?). J'ai eu des compilateurs de rendre non valide optimisations (par exemple, il y a quelques années, j'ai eu un CPI (11.0, iirc) utiliser signé sur 32 bits-int-de-double conversion en 1.0/n
où n
était unsigned int
. A été deux fois plus rapide que gcc est de sortie. Mais mal, beaucoup de valeurs ont été plus grand que 2^31
, oups.).