0.00 和 -0.00 的 C 错误
C bug of 0.00 and -0.00
C program to find the rank of the matrix.
我使用高斯消去法来确定矩阵的秩。 This is the method which I have used.
我的代码在 c:
#include<stdio.h>
#include<stdlib.h>
#define min(x,y) x>y?y:x
float** create_matrix(int,int);
void input(float**,int,int);
void display(float**,int,int);
void matrix_op(float**,int,int,int,float);
void row_trans(float**,int,int);
void row_swap(float**,int,int,int);
int rank(float**,int,int);
int main()
{
int row,col;
printf("Enter number of rows and columns: ");
scanf("%d %d",&row,&col);
float** matrix=create_matrix(row,col);
input(matrix,row,col);
printf("The rank of the matrix is: %d\n",rank(matrix,row,col));
return 0;
}
float** create_matrix(int r,int c)
{
int i;
float** matrix=(float**)calloc(r,sizeof(float*));
for(i=0;i<r;i++)
*(matrix+i)=(float*)calloc(c,sizeof(float));
return matrix;
}
void input(float** matrix,int r,int c)
{
int i,j;
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
scanf("%f",&matrix[i][j]);
}
}
void display(float** matrix,int r,int c)
{
int i,j;
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
printf("%.2f ",matrix[i][j]);
printf("\n");
}
}
void matrix_op(float** matrix,int c,int j,int i,float scalar)
{
int k;
for(k=0;k<c;k++)
{
matrix[j][k]+=matrix[i][k]*scalar;
}
}
void row_trans(float** matrix,int r,int i)
{
if(matrix[i][i]!=0)
{
for(int j=i+1;j<r;j++)
{
if(j==i)
continue;
if(matrix[j][i]!=0)
matrix_op(matrix,r,j,i,(-1.00)*(matrix[j][i]/matrix[i][i]));
}
}
else
{
int j=i+1;
while(j<r)
{
if(matrix[j][i]==0)
j+=1;
else
break;
}
if(j!=r)
{
row_swap(matrix,r,i,j);
row_trans(matrix,r,i);
}
}
}
void row_swap(float** matrix,int c,int i,int j)
{
for(int k=0;k<c;k++)
{
float temp=matrix[i][k];
matrix[i][k]=matrix[j][k];
matrix[j][k]=temp;
}
}
int rank(float** matrix,int r,int c)
{
int i;
int l=min(r,c);
for(i=0;i<l;i++)
{
row_trans(matrix,r,i);
display(matrix,r,c);
printf("\n");
}
i=r-1;
while(i>=0)
{
if(matrix[i][l-1]==0)
i-=1;
else
break;
}
return i+1;
}
当我输入这个时:
Enter number of rows and columns: 5 5
3 -1 -2 3 -1
4 1 2 5 4
7 10 10 2 -3
2 -3 -6 1 -6
3 9 8 -3 -7
我明白了:
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 12.33 14.67 -5.00 -0.67
0.00 -2.33 -4.67 -1.00 -5.33
0.00 10.00 10.00 -6.00 -6.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 -10.00 -10.29 -28.86
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 -0.00 -0.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 0.00 0.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 0.00 0.00
The rank of the matrix is: 4
注意 -0.00 和 0.00 被认为是不同的。
这就是为什么我的排名是 4,而排名应该是 3。
编辑 1:在最终显示中我们可以看到,在最后一列中,倒数第二行是 -0.00,最后一行是 0.00。在函数 rank()
中, i 迭代最后一列的零,然后它将 return rows- #(zeroes)
。但是没有考虑-0.00=0.00.
编辑 2:使用 double 后我遇到了同样的问题。调试后我得到了这个,
115 while(i>=0)
(gdb) p i
= 3
(gdb) n
117 if(matrix[i][l-1]==0)
(gdb) p matrix[i][l-1]
= 8.8817841970012523e-16
(gdb) p matrix[i][l-1]==0
= 0
编辑 3:
引入精度后问题解决
double set_prec(double n)
{
return floor(pow(10,3)*n)/pow(10,3);
}
如有任何帮助,我们将不胜感激。
感谢期待。
不是与 0
进行比较,而是与 epsilon
进行比较
double epsilon = 1E-12; // tweak as you deem fit
//if (a != 0)
if (fabs(a) > epsilon)
//if (a == 0)
if (fabs(a) < epsilon)
//if (a == b)
if (fabs(a - b) < epsilon)
当您使用 %.2f
在 C 中打印数字时,C 实现会将其四舍五入到小数点后两位。诸如 0.003… 或 −0.0001… 之类的数字将打印为 0.00
或 -0.00
。因此,一个数字打印为 0.00
的事实并不意味着它是 0。从您报告的行为来看,很明显您的程序中的数字不是 0 或 −0。 (IEEE 754 算法有一个 −0,在数学上是 0,但保留符号作为程序员可能使用的信息。它比较等于 +0。)
浮点运算仅近似于实数运算。当您以普通方式使用浮点运算时,任何计算结果 x
只是您使用实数运算得到的结果 x 的近似值。由于您只计算了 x
而不是 x,您没有关于 x 是什么的完整信息,因此它是 不可能,不经过专门的分析和设计,才能准确知道x是什么。因此,如果某个结果 x
接近于 0,则无法知道 x 是否为 0。
一般来说,浮点数结果x
与拉尔数结果x之间的差可以从0到无穷大,甚至可以是“不一个号码。”在使用由小整数输入组成的小矩阵进行高斯消去法的特定情况下,可以证明足够接近 0 的浮点结果对应于如果使用实数算术计算则为 0 的结果。在那种情况下,将接近 0 的结果当作 0 来处理可能会产生正确的结果。
这通常不是正确的解决方案,通常不建议将浮点结果四舍五入为 0 或与公差进行比较。它仅在特定情况下有用有限的情况。
C program to find the rank of the matrix.
我使用高斯消去法来确定矩阵的秩。 This is the method which I have used.
我的代码在 c:
#include<stdio.h>
#include<stdlib.h>
#define min(x,y) x>y?y:x
float** create_matrix(int,int);
void input(float**,int,int);
void display(float**,int,int);
void matrix_op(float**,int,int,int,float);
void row_trans(float**,int,int);
void row_swap(float**,int,int,int);
int rank(float**,int,int);
int main()
{
int row,col;
printf("Enter number of rows and columns: ");
scanf("%d %d",&row,&col);
float** matrix=create_matrix(row,col);
input(matrix,row,col);
printf("The rank of the matrix is: %d\n",rank(matrix,row,col));
return 0;
}
float** create_matrix(int r,int c)
{
int i;
float** matrix=(float**)calloc(r,sizeof(float*));
for(i=0;i<r;i++)
*(matrix+i)=(float*)calloc(c,sizeof(float));
return matrix;
}
void input(float** matrix,int r,int c)
{
int i,j;
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
scanf("%f",&matrix[i][j]);
}
}
void display(float** matrix,int r,int c)
{
int i,j;
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
printf("%.2f ",matrix[i][j]);
printf("\n");
}
}
void matrix_op(float** matrix,int c,int j,int i,float scalar)
{
int k;
for(k=0;k<c;k++)
{
matrix[j][k]+=matrix[i][k]*scalar;
}
}
void row_trans(float** matrix,int r,int i)
{
if(matrix[i][i]!=0)
{
for(int j=i+1;j<r;j++)
{
if(j==i)
continue;
if(matrix[j][i]!=0)
matrix_op(matrix,r,j,i,(-1.00)*(matrix[j][i]/matrix[i][i]));
}
}
else
{
int j=i+1;
while(j<r)
{
if(matrix[j][i]==0)
j+=1;
else
break;
}
if(j!=r)
{
row_swap(matrix,r,i,j);
row_trans(matrix,r,i);
}
}
}
void row_swap(float** matrix,int c,int i,int j)
{
for(int k=0;k<c;k++)
{
float temp=matrix[i][k];
matrix[i][k]=matrix[j][k];
matrix[j][k]=temp;
}
}
int rank(float** matrix,int r,int c)
{
int i;
int l=min(r,c);
for(i=0;i<l;i++)
{
row_trans(matrix,r,i);
display(matrix,r,c);
printf("\n");
}
i=r-1;
while(i>=0)
{
if(matrix[i][l-1]==0)
i-=1;
else
break;
}
return i+1;
}
当我输入这个时:
Enter number of rows and columns: 5 5
3 -1 -2 3 -1
4 1 2 5 4
7 10 10 2 -3
2 -3 -6 1 -6
3 9 8 -3 -7
我明白了:
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 12.33 14.67 -5.00 -0.67
0.00 -2.33 -4.67 -1.00 -5.33
0.00 10.00 10.00 -6.00 -6.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 -10.00 -10.29 -28.86
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 -0.00 -0.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 0.00 0.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 0.00 0.00
The rank of the matrix is: 4
注意 -0.00 和 0.00 被认为是不同的。 这就是为什么我的排名是 4,而排名应该是 3。
编辑 1:在最终显示中我们可以看到,在最后一列中,倒数第二行是 -0.00,最后一行是 0.00。在函数 rank()
中, i 迭代最后一列的零,然后它将 return rows- #(zeroes)
。但是没有考虑-0.00=0.00.
编辑 2:使用 double 后我遇到了同样的问题。调试后我得到了这个,
115 while(i>=0)
(gdb) p i
= 3
(gdb) n
117 if(matrix[i][l-1]==0)
(gdb) p matrix[i][l-1]
= 8.8817841970012523e-16
(gdb) p matrix[i][l-1]==0
= 0
编辑 3: 引入精度后问题解决
double set_prec(double n)
{
return floor(pow(10,3)*n)/pow(10,3);
}
如有任何帮助,我们将不胜感激。 感谢期待。
不是与 0
进行比较,而是与 epsilon
double epsilon = 1E-12; // tweak as you deem fit
//if (a != 0)
if (fabs(a) > epsilon)
//if (a == 0)
if (fabs(a) < epsilon)
//if (a == b)
if (fabs(a - b) < epsilon)
当您使用 %.2f
在 C 中打印数字时,C 实现会将其四舍五入到小数点后两位。诸如 0.003… 或 −0.0001… 之类的数字将打印为 0.00
或 -0.00
。因此,一个数字打印为 0.00
的事实并不意味着它是 0。从您报告的行为来看,很明显您的程序中的数字不是 0 或 −0。 (IEEE 754 算法有一个 −0,在数学上是 0,但保留符号作为程序员可能使用的信息。它比较等于 +0。)
浮点运算仅近似于实数运算。当您以普通方式使用浮点运算时,任何计算结果 x
只是您使用实数运算得到的结果 x 的近似值。由于您只计算了 x
而不是 x,您没有关于 x 是什么的完整信息,因此它是 不可能,不经过专门的分析和设计,才能准确知道x是什么。因此,如果某个结果 x
接近于 0,则无法知道 x 是否为 0。
一般来说,浮点数结果x
与拉尔数结果x之间的差可以从0到无穷大,甚至可以是“不一个号码。”在使用由小整数输入组成的小矩阵进行高斯消去法的特定情况下,可以证明足够接近 0 的浮点结果对应于如果使用实数算术计算则为 0 的结果。在那种情况下,将接近 0 的结果当作 0 来处理可能会产生正确的结果。
这通常不是正确的解决方案,通常不建议将浮点结果四舍五入为 0 或与公差进行比较。它仅在特定情况下有用有限的情况。