C++ 如何检查两个矩阵是否相同?

C++ 如何检查两个矩阵是否相同?,c++,c++11,matrix,c++14,eigen,C++,C++11,Matrix,C++14,Eigen,这个想法是将两个矩阵相乘。并使用特征值进行相同的乘法,然后检查结果是否相同 在下面的示例中,makeN=2返回相同的东西,但N=1000返回不相同的东西。为什么? #include <cstdlib> #include <iostream> #include <Eigen/Dense> using namespace std; using namespace Eigen; const int N = 1000; void mult_matrix(doub

这个想法是将两个矩阵相乘。并使用特征值进行相同的乘法,然后检查结果是否相同

在下面的示例中,make
N=2
返回
相同的东西
,但
N=1000
返回
不相同的东西
。为什么?

#include <cstdlib>
#include <iostream>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

const int N = 1000;

void mult_matrix(double x[N][N], double y[N][N], double z[N][N]) {
    int rows = N;
    int cols = N;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < cols; j++)
            for (int k = 0; k < cols; k++)
                z[i][j] += x[i][k] * y[k][j];
}

void check(double *x, double *y, double *z) {

    Matrix<double, Dynamic, Dynamic, RowMajor> m = 
            Matrix<double, Dynamic, Dynamic, RowMajor>::Map(x, N, N) * 
            Matrix<double, Dynamic, Dynamic, RowMajor>::Map(y, N, N);

    cout << m(0, 0) << endl;
    cout << Matrix<double, Dynamic, Dynamic, RowMajor>::Map(z, N, N)(0, 0) << endl;

    if (m == Matrix<double, Dynamic, Dynamic, RowMajor>::Map(z, N, N))
        cout << "same thing" << endl;
    else
        cout << "NOT same thing" << endl;
}

int main() {
    double *a = (double*)malloc(N*N*sizeof(double));
    double *b = (double*)malloc(N*N*sizeof(double));
    double *c = (double*)malloc(N*N*sizeof(double));

    Matrix<double, Dynamic, Dynamic, RowMajor>::Map(a, N, N).setRandom();
    Matrix<double, Dynamic, Dynamic, RowMajor>::Map(b, N, N).setRandom();
    Matrix<double, Dynamic, Dynamic, RowMajor>::Map(c, N, N).setZero();

    mult_matrix((double (*)[N])a, (double (*)[N])b, (double (*)[N])c);
    check(a, b, c);
}
#包括
#包括
#包括
使用名称空间std;
使用名称空间特征;
常数int N=1000;
void mult_矩阵(双x[N][N],双y[N][N],双z[N][N]){
int行=N;
int cols=N;
对于(int i=0;icout由于舍入错误,将浮点数与
=
运算符进行比较会出现错误。因此对于
N=2
,它可能会工作,但对于较大的
N
,它很可能会失败

尝试以下比较器,而不是
==

bool double_equals(double a, double b, double epsilon = 0.001)
{
    return std::abs(a - b) < epsilon;
}
bool double_等于(双a,双b,双ε=0.001)
{
返回std::abs(a-b)
以下是@Jonathan Leffler的评论,上面的比较器并不理想,因为使用相对差比绝对差更好

double reldiff(double a, double b) {
    double divisor = fmax(fabs(a), fabs(b)); /* If divisor is zero, both x and y are zero, so the difference between them is zero */
    if (divisor == 0.0) return 0.0; return fabs(a - b) / divisor; 
}

bool double_equals(double a, double b, double rel_diff)
{
    return reldiff(a, b) < rel_diff;
}
double reldiff(双a,双b){
双除数=fmax(fabs(a),fabs(b));/*如果除数为零,x和y都为零,那么它们之间的差值为零*/
if(除数==0.0)返回0.0;返回fabs(a-b)/除数;
}
布尔双_等于(双a,双b,双相对差)
{
返回reldiff(a,b)
由于舍入错误,将浮点数与
=
运算符进行比较会出现错误。因此对于
N=2
,它可能会工作,但对于较大的
N
,它很可能会失败

尝试以下比较器,而不是
==

bool double_equals(double a, double b, double epsilon = 0.001)
{
    return std::abs(a - b) < epsilon;
}
bool double_等于(双a,双b,双ε=0.001)
{
返回std::abs(a-b)
以下是@Jonathan Leffler的评论,上面的比较器并不理想,因为使用相对差比绝对差更好

double reldiff(double a, double b) {
    double divisor = fmax(fabs(a), fabs(b)); /* If divisor is zero, both x and y are zero, so the difference between them is zero */
    if (divisor == 0.0) return 0.0; return fabs(a - b) / divisor; 
}

bool double_equals(double a, double b, double rel_diff)
{
    return reldiff(a, b) < rel_diff;
}
double reldiff(双a,双b){
双除数=fmax(fabs(a),fabs(b));/*如果除数为零,x和y都为零,那么它们之间的差值为零*/
if(除数==0.0)返回0.0;返回fabs(a-b)/除数;
}
布尔双_等于(双a,双b,双相对差)
{
返回reldiff(a,b)
不是答案,但评论太长

坏消息是无法比较两个浮点值是否相等

由于表示的有限性,即有效位数的有限性,不可避免地会出现截断错误。例如,
0.1
将不会精确地表示为
0.1
,而是表示为类似
0.999999999933
0.1000000000002
(虚构值)的值。精确值可能取决于特定的基转换算法和舍入策略

在幸运的情况下,当您进行计算时,耳轴误差会逐渐累积,因此有效位数也会逐渐减少。因此,使用有界相对误差测试是否相等是有意义的,例如:

|a - b| < max(|a|, |b|).ε
| a-b |
其中
ε
接近机器精度(对于单精度,约
10^-7

但在不吉利的情况下,比如导数的数值计算,就会出现所谓灾难性相消的现象:当你减去两个附近的值时,精确的有效位数会急剧下降

例如
(sin(1.000001)-sin(1))/0.000001=(0.84147104-0.84147100)/0.0000001=0.40000000
,而精确值应为
0.5403023

当两个向量接近垂直时,矩阵乘积会发生灾难性的相消,相对误差准则就不起作用了


最糟糕的情况是,当你想检查一个数量是否为零时,比如在寻找一个函数的根时:“接近零”的值可以有任意数量级(想想同样问题的解决方案,当变量以米表示,然后以毫米表示)没有相对误差标准可以起作用,但即使绝对误差也不能起作用,除非你有关于震级的额外信息。没有通用比较器可以起作用。

不是答案,但注释太长

坏消息是无法比较两个浮点值是否相等

由于表示的有限性,即有效位数的有限性,不可避免地会出现截断错误。例如,
0.1
将不会精确地表示为
0.1
,而是表示为类似
0.999999999933
0.1000000000002
(虚构值)的值。精确值可能取决于特定的基转换算法和舍入策略

在幸运的情况下,当您进行计算时,耳轴误差会逐渐累积,因此有效位数也会逐渐减少。因此,使用有界相对误差测试是否相等是有意义的,例如:

|a - b| < max(|a|, |b|).ε
| a-b |
其中
ε
接近机器精度(对于单精度,约
10^-7

但在不吉利的情况下,比如导数的数值计算,就会出现所谓灾难性相消的现象:当你减去两个附近的值时,精确的有效位数会急剧下降

例如
(sin(1.000001)-sin(1))/0.000001=(0.84147104-0.84147100)/0.0000001=0.40000000
,而精确值应为
0.5403023