Soit N
être un entier non signé au moment de la compilation.
GCC peut optimiser
unsigned sum = 0;
for(unsigned i=0; i<N; i++) sum += a; // a is an unsigned integer
pour simplement a*N
. Cela peut être compris puisque l'arithmétique modulaire dit (a%k + b%k)%k = (a+b)%k
.
Cependant, GCC n'optimisera pas
float sum = 0;
for(unsigned i=0; i<N; i++) sum += a; // a is a float
à a*(float)N
.
Mais en utilisant les mathématiques associatives avec, par exemple. -Ofast
J'ai découvert que GCC peut réduire ceci dans l'ordre log2(N)
étapes. Par exemple, pour N=8
il peut faire la somme en trois additions.
sum = a + a
sum = sum + sum // (a + a) + (a + a)
sum = sum + sum // ((a + a) + (a + a)) + ((a + a) + (a + a))
Bien que quelque temps après N=16
Le CCG reprend ses activités N-1
des sommes.
*Ma question est de savoir pourquoi GCC ne fait pas `a(float)Ncon
-Ofast` ?**
Au lieu d'être O(N)
o O(Log(N))
cela pourrait être simplement O(1)
. Puisque N
est connu au moment de la compilation, il est possible de déterminer si N
s'insère dans un flotteur. Et même si N
est trop grand pour un flotteur, il pourrait faire sum =a*(float)(N & 0x0000ffff) + a*(float)(N & ffff0000)
. En fait, j'ai fait un petit test pour vérifier la précision et a*(float)N
est de toute façon plus précise (voir le code et les résultats ci-dessous).
//gcc -O3 foo.c
//don't use -Ofast or -ffast-math or -fassociative-math
#include <stdio.h>
float sumf(float a, int n)
{
float sum = 0;
for(int i=0; i<n; i++) sum += a;
return sum;
}
float sumf_kahan(float a, int n)
{
float sum = 0;
float c = 0;
for(int i=0; i<n; i++) {
float y = a - c;
float t = sum + y;
c = (t -sum) - y;
sum = t;
}
return sum;
}
float mulf(float a, int n)
{
return a*n;
}
int main(void)
{
int n = 1<<24;
float a = 3.14159;
float t1 = sumf(a,n);
float t2 = sumf_kahan(a,n);
float t3 = mulf(a,n);
printf("%f %f %f\n",t1,t2,t3);
}
Le résultat est 61848396.000000 52707136.000000 52707136.000000
ce qui montre que la multiplication et la Résumé de Kahan ont le même résultat, ce qui montre, je pense, que la multiplication est plus précise que la simple somme.