Résultats incohérents (C)?

Dans ce programme, j’ai codé plusieurs formules et, pour une formule, j’obtiens des résultats incohérents, même s’il s’agit du même code et des mêmes entrées pour chaque exécution. La fonction en question est “WqFormula”. Le résultat correct est 0,041667 pour certaines exécutions et 0,000000 pour les autres exécutions. Je comstack sous Ubuntu (64 bits) avec GCC 4.6.3. Une autre chose est que j’ai essayé de comstackr et d’exécuter ceci sur un PC en utilisant GCC 4.4.6 et cela m’a donné des résultats complètement différents pour chaque formule. Heres le code:

float PoFormula(float, float, int); float LFormula(float, float, int); float WFormula(float, float, int); float LqFormula(float, float, int); float WqFormula(float, float, int); int main() { int n, m; //# of arrivals, # of service channels float mu, lambda; //avg serviced, arrivals in time period printf("lambda (l) = "); scanf ("%f", &lambda); printf("mu (m) = "); scanf ("%f", &mu); printf("m (M) = "); scanf("%i", &m); float test, test2, test3, test4, test5; test = PoFormula(lambda, mu, m); printf("PoFormula is %f\n", test); test2 = LFormula(lambda, mu, m); printf("LFormula is %f\n", test2); test3 = WFormula(lambda, mu, m); printf("WFormula is %f\n", test3); test4 = LqFormula(lambda, mu, m); printf("LqFormula is %f\n", test4); test5 = WqFormula(lambda, mu, m); printf("WqFormula is %f\n", test5); return; } float PoFormula(float lambda, float mu, int m) { float summation, factorial = 1; int i, j; for (i=0; i < (m); i++) { for (j=1; j < (i+1); j++) factorial *= j; factorial = 1 / factorial; factorial = factorial * pow ((lambda/mu), i); summation += factorial; } factorial = 1; for (j=1; j < (m+1); j++) factorial *= j; factorial = 1 / factorial; factorial = factorial * pow ((lambda/mu), m); factorial = factorial * ((m*mu)/((m*mu) - lambda)); factorial += summation; factorial = 1 / factorial; return factorial; } float LFormula(float lambda, float mu, int m) { float factorial = 1, po; int j; po = PoFormula(lambda, mu, m); for (j=1; j < (m); j++) factorial *= j; factorial *= pow(((m*mu) - lambda), 2); factorial = (((lambda*mu)*(pow((lambda/mu),m)))/factorial) * po; factorial += (lambda/mu); return factorial; } float WFormula(float lambda, float mu, int m) { float factorial = LFormula(lambda, mu, m); factorial /= lambda; return factorial; } float LqFormula(float lambda, float mu, int m) { float factorial = LFormula(lambda, mu, m); factorial -= (lambda/mu); return factorial; } float WqFormula(float lambda, float mu, int m) { float factorial = LqFormula(lambda, mu, m); factorial /= lambda; return factorial; } 

Ce qui devrait être imprimé à chaque fois est ceci:

PoFormula est 0.500000

LFormula est 0.750000

WFormula est 0.375000

LqFormula est 0.083333

WqFormula est 0.041667

Je serai heureux de fournir plus d’informations si besoin est.

La fonction suivante utilise la summation sans l’initialiser:

 float PoFormula(float lambda, float mu, int m) { float summation, factorial = 1; for (i=0; i < (m); i++) { // .... summation += factorial; } 

Vous ne pouvez donc pas vous attendre à ce que les résultats de cette fonction soient significatifs.

Votre compilateur peut vous prévenir de tels problèmes, si vous le lui demandez (et vous devriez le faire!):

Pour GCC, comstackz avec -Wall -Wextra (personnellement, j'utilise aussi -pedantic , YMMV) pour obtenir autant d'avertissements que possible. Cependant, dans ce cas particulier, GCC semble ignorer le problème jusqu'à ce que vous activiez l'optimisation à l' aide de -O .

Vous pouvez arrêter de lire maintenant et simplement utiliser -Wall -Wextra -O lors de la compilation pour résoudre ce problème.


L'parsing des variables non initialisées de GCC a deux contrôles différents: " définitivement utilisé non initialisé" et " éventuellement utilisé non initialisé". L'parsing fonctionne différemment selon que l'optimisation est activée ou non:

  • Si l'optimisation est désactivée ( -O0 , par défaut), le compilateur effectue les deux vérifications en une seule parsing.
  • Si l'optimisation est activée, le compilateur effectue à la place deux passes: la première passe uniquement à la vérification "définitivement non initialisée", la seconde après l'optimisation (car l'optimisation peut modifier le stream de contrôle) et effectue les deux vérifications.

Je ne connais pas suffisamment les éléments internes de GCC pour savoir ce qui cache ce problème dans votre code, mais je l'ai réduit à ce scénario , si quelqu'un souhaite approfondir davantage. Si vous déroulez la boucle, vous obtenez l'avertissement même sans -O . Les optimisations de déroulement de boucle peuvent donc avoir quelque chose à voir avec cela.


Si vous utilisez MSVC, comstackz avec /W4 pour obtenir le plus d'avertissements. MSVC signale cette variable non initialisée comme un problème au niveau d'avertissement par défaut, avec et sans optimisation.