【问题标题】:C++ program for Gauss Jordan elimination returning a very small value but not 0用于高斯乔丹消除的 C++ 程序返回一个非常小的值但不是 0
【发布时间】:2021-09-15 16:01:29
【问题描述】:

我编写了一个程序来使用 Gauss Jordan 消元法求解线性方程组。程序运行正常,但在某些情况下,它不会给出 0 的答案,而是返回一个非常小的值。

#include<iostream>
#include<iomanip>
#include<cassert>
#define N 10
using namespace std;

//printing out the array
void print(float x[][N], int n){
    for(int i=0;i<n;i++){
        for(int j=0;j<=n;j++)
            cout << setprecision(5) << setw(15) <<x[i][j];
        cout << endl;
    }
    cout << endl;
}

//to normalise the leading entries to 1
void normalize(float x[][N], int n, int i, int j){
    float fac = x[i][j];
    for(int k=0;k<=n;k++)
        x[i][k] /= fac;
}

//check if the leading entry is a zero
bool chk_zero(float x[][N], int n, int i){
    int j, k, c{0};
    if(x[i][i]==0){
    for(j=i;j<n-1;j++){
        c=1;
        while(x[j+c][i]==0 && i+c<n){
            c++;
            if(i+c==n-1)
                assert(i+c==n-1 && "Equation has no solution");
                return false;
            }

        for(k=0;k<=n;k++){
            swap(x[i][k], x[i+c][k]);
            }
        return true;

        }
    }
    return true;

}

//Gauss Jordan elimination method
void GaussJordan(float x[][N], int n){
    int i, j, k, c;
    float rat;

    for(i=0;i<n;i++){
        //not taking the zero in pivot column case
        chk_zero(x, n, i);
        normalize(x, n, i, i);

        for(j=0;j<n;j++){
            if (i != j){
               float fac{x[j][i]};
               for(k=0;k<=n;k++)
                   x[j][k] = x[j][k]-fac*x[i][k];
            }
        }
    }
}



int main(){
    float arr[][N] = { {0, 5, 1, 2},
                       {2, 11, 5, 3},
                       {1, 0, 0, 0} };

    int n = sizeof(arr)/sizeof(arr[0]);

    print(arr, n);

    GaussJordan(arr, n);

    cout << n << endl;

    print(arr, n);
    return 0;
}

我得到的输出是:

 1              0              0     2.3842e-08
 0              1              0            0.5
-0             -0              1           -0.5

我应该得到的输出是:

 1              0              0              0
 0              1              0            0.5
-0             -0              1           -0.5

值 2.3842e-08 应该为零。是因为C++中浮点数的精度吗?

如果是这样,我应该怎么做才能将如此低的值舍入为 0 而不会丢失数据?

还有,为什么是“-0”而不是0。

【问题讨论】:

  • 您是否尝试过在调试器中逐句执行代码,同时监控所有变量及其值?
  • 我还建议您始终如一地重新缩进您的代码(体面的编辑器具有为您执行此操作的功能),因为这样可以更容易地查看一些可能的错误。其他可能的错误包括永远无法到达的语句。
  • 该程序几乎在所有情况下都可以正常工作,但有时它不会返回 0,而是打印一个非常小的接近 0 的值。我遇到的唯一错误是一个值趋于零但不为零。
  • 我应该怎么做才能将如此低的值舍入为 0 而不会丢失数据 - 你无能为力。浮点数学本质上是不精确的。您可以做的是通过使用一些技巧(如部分旋转)来提高精度。

标签: c++ matrix linear-algebra


【解决方案1】:

值 2.3842e-08 应该为零。是因为C++中浮点数的精度吗?

是的。

如果是这样,我应该怎么做才能将如此低的值四舍五入为 0 而不会丢失数据?

您可以使用epsilon 值来决定浮点值是否被视为0:

const float epsilon = 0.000001; // Depends on the use case of your application
if (std::abs(some_float) < epsilon) {
    // Treat some_float as 0
}

但是,这种方法有一些缺点。阅读here了解更多信息。

还有,为什么是“-0”而不是0。

这是因为浮点数的表示方式。大多数 C++ 编译器使用IEEE 754 标准来实现浮点运算。


补充几点(与问题无关):

  • 您应该避免使用using namespace std,因为它会污染全局命名空间。特别是对于大型代码库。
  • 使用std::array&lt;&gt; 而不是原始数组,因为它们更安全。

【讨论】:

  • 我明白你所说的,但是线性代数的其他“库/程序”如何克服这个问题? epsilon解不是万无一失的,还是有其他算法来评估矩阵?
  • @Circuit_Breaker0.7 看看ttmath.orgen.wikipedia.org/wiki/…,如果你想要更多选择。
【解决方案2】:

值 2.3842e-08 应该为零。 是因为C++中浮点数的精度吗?

没有。它是根据 IEEE-754 标准在二进制数系统中浮点数表示的一个特征。它以硬件实现,几乎所有语言都使用它。所有浮点计算都是在错误的情况下执行的,因此您应该为 FPU 设置正确的舍入模式。详见

【讨论】:

    猜你喜欢
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    相关资源
    最近更新 更多