【3月6日実施】システムメンテナンス実施のお知らせ

昔 Delphi で作成したものを C で書き直しました。Delphi ではまったく問題なかったのですが、C の場合、方程式の係数によって、掃き出し処理をした後 0 にマイナスが付加されることがあります。書式指定しない printf でも同じです。
 なぜでしょうか?
※解は正しいです。

#include <stdio.h>
#include <math.h>
#define M 5

/* これは掃き出し処理、後単位行列になった 0 成分にマイナスがついてしまう
double A[M][M+1] = {
   { 5.0, -3.0, -3.0, 3.0, 2.0, -8.0 },
   { 9.0, -7.0, 1.0, -6.0, -5.0, -3.0 },
   { -1.0, -1.0, -8.0, 7.0, 4.0, -4.0 },
   { -7.0, 2.0, -6.0, 0.0, -1.0, -1.0 },
   { 8.0, 5.0, -3.0, 9.0, -7.0, 5.0 }
};
*/

double A[M][M+1] = { // こちらはOK
   { 2.0, 0.0, 4.0, 2.0, 0.0, 0.0 },
   { 2.0, 2.0, 0.0, 4.0, 8.0,12.0 },
   { 2.0, 4.0, 4.0, 0.0, 2.0, 0.0 },
   { 4.0, 2.0, 0.0, 0.0, 4.0, 0.0 },
   { 4.0, 0.0, 2.0, 2.0, 4.0, 8.0 }
};

//Gauss Jordan
int GaussJordan(int N)
{
  double mMax, R_pivot, pivot, temp;
  int pRow = -1;
  for (int pv = 0; pv < N; pv++) //行ループ(一番外側のループ)
  {
    mMax = 0.000000001;
    for (int k = pv; k < N; k++) {//行ループ ピボット行以下の最大値探索
      if (abs(A[k][pv]) > mMax){
        mMax = abs(A[k][pv]);
        pRow = k;
      }
    }
    if (mMax <= 0.000000001){ //0対策
      printf("解が存在しないか、または不定です!");
      return (0);
    }

    if (pv != pRow) //行の入れ替え
    {
      for (int k = 0; k < N + 1; k++) { //列ループ
        temp = A[pv][k];
        A[pv][k] = A[pRow][k];
        A[pRow][k] = temp;
      }
    }

    //ピボット行 A[pv][j] の処理
    pivot = A[pv][pv];
    R_pivot = 1.0 / pivot;
    for (int j = 0; j < N + 1; j++)   //列ループ
      A[pv][j] = A[pv][j] * R_pivot;  //A[pv][pv] = 1 となる

    //ピボット行以外の処理 ⇒ ピボット列を 0 にする。
    for (int k = 0; k < N; k++){ //行ループ
      temp = A[k][pv];         //各行のピボット列成分
      for (int j = pv; j < N + 1; j++) //ピボット列以降を処理
        if (k != pv)
          A[k][j] = A[k][j] - temp * A[pv][j];
    }
  }
  return (1);
}

int main(void) {
  printf("連立一次方程式\n");
  for (int i = 0; i < M; i++) {
    for (int j = 0; j < M+1; j++)
      printf("%8.3g",A[i][j]);
    printf("\n");
  }

  GaussJordan(M);
  printf("\n解\n");
  for (int i = 0; i < M; i++) {
    for (int j = 0; j < M+1; j++)
      printf("%8.3g",A[i][j]);
    printf("\n");
  }
}

「C 言語の Gauss Jordan 法」の質問画像

質問者からの補足コメント

  • > %.20f みたいにぎりぎりまで表示するように出力を指定すれば, どっちかは区別がつく.

     やはり、マイナスがつきますね。
     ま、これを表示させる必要はほとんどないのでとくに問題はないのですけど、何か引っかかる(笑)。

     ちなみにC#ではこんな症状は生じませんでした。

    「C 言語の Gauss Jordan 法」の補足画像1
      補足日時:2022/12/28 13:35

A 回答 (2件)

IEEE754の浮動小数点数にはゼロの正負がありますから、値として負のゼロならマイナス記号が付くのは当然のことです。


あるいは-0と表示されていても実際には-1e-10とかの小さな負の値の可能性もあります。書式指定していないときは本当に-0だと思いますけど。
-0の表示を回避したければ-0を0に置き換える処理を入れる必要があるでしょう。
    • good
    • 0
この回答へのお礼

回答まことにありがとうございました。

お礼日時:2022/12/28 13:38

・負で 0 に近い数を表示するときに出力指定の影響で「-0」になっている


・実際に値が -0 である (double の形式は処理系依存だが IEEE 60559 では +0 と -0 のどちらも存在する)
のどちらか, かなぁ.

%.20f みたいにぎりぎりまで表示するように出力を指定すれば, どっちかは区別がつく.
    • good
    • 0
この回答へのお礼

回答まことにありがとうございました。

お礼日時:2022/12/28 13:37

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!