3

このプログラムでは、いくつかの数式をコーディングしましたが、すべての実行で同じコードと入力であるにもかかわらず、1つの数式で一貫性のない結果が得られています。問題の関数は「WqFormula」です。一部の実行では0.041667の正しい結果が得られ、他の実行では0.000000が得られます。GCC 4.6.3を使用してUbuntu(64ビット)でコンパイルしています。もう1つは、GCC 4.4.6を使用してPCでこれをコンパイルして実行しようとしたところ、数式ごとにまったく異なる結果が得られました。コードは次のとおりです。

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

毎回印刷する必要があるのはこれです:

PoFormulaは0.500000です

LFormulaは0.750000です

WFormulaは0.375000です

LqFormulaは0.083333です

WqFormulaは0.041667です

必要に応じて、さらに詳しい情報を提供させていただきます。

4

1 に答える 1

3

次の関数はsummation、初期化せずに使用します。

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

したがって、この関数の結果に意味があるとは期待できません。

あなたがそれを頼んだ場合、あなたのコンパイラはこのような問題についてあなたに警告することができます(そしてあなたは本当にそうすべきです!):

GCCの場合は、-Wall -Wextra(個人的には-pedantic、YMMVも使用します)でコンパイルして、できるだけ多くの警告を取得します。ただし、この特定のケースでは、を使用して最適化を有効にするまで、GCCは問題を認識していないよう-Oです。

今すぐ読むのをやめて-Wall -Wextra -O、コンパイル時にこの問題をキャッチするために使用することができます。


GCCの初期化されていない変数分析には、「確実に初期化されていないものを使用した」と「おそらく初期化されていないものを使用した」という2つの異なるチェックがあります。最適化が有効になっているかどうかによって、分析の動作は異なります。

  • 最適化がオフ(-O0デフォルト)の場合、コンパイラーは1回の分析パスで両方のチェックを実行します。
  • 最適化がオンの場合、コンパイラは代わりに2つのパスを実行します。最初のパスは「完全に初期化されていない」チェックのみを実行し、2番目のパスは最適化後に実行され(最適化によって制御フローが変更される可能性があるため)、両方のチェックを実行します。

私はGCCの内部に十分な知識がなく、コードでこの問題を隠すために何が起こるかを確認できませんが、誰かがもっと深く掘り下げたい場合は、このテストケースに減らしました。ループを展開すると、がなくても警告が表示される-Oため、ループ展開の最適化はそれと関係がある可能性があります。


MSVCを使用している場合は、でコンパイルし/W4て最も多くの警告を取得します。MSVCは、この初期化されていない変数を、最適化の有無にかかわらず、デフォルトの警告レベルの問題として報告します。

于 2012-09-23T08:06:27.427 に答える