MAtrix乘法中的分段错误

时间:2014-12-21 11:23:24

标签: c++

我是C / C ++的初学者。我试图使用Matrix Exponentiation实现一个程序来返回第n个Fibonacci数的值。我写了下面的代码:

#include <cmath>
#include <iostream>

using namespace std;

typedef struct Matrix {
    unsigned long long a_00;
    unsigned long long a_01;
    unsigned long long a_10;
    unsigned long long a_11;
}Matrix;

Matrix* init_matrix(unsigned long long n);
Matrix* init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11);
Matrix* mult_matrix(Matrix* A, Matrix* B);      
Matrix* expo_matrix(Matrix* A,unsigned int n);
unsigned long long fib_matrix_expo(unsigned int n); 

int main() {

    unsigned int n;
    cin >> n;

    unsigned long long result = fib_matrix_expo(n);
    cout << result << endl;
    return 0;
}


Matrix* init_matrix(unsigned long long n) {
    Matrix* ret_matrix = (Matrix*)::operator new (sizeof(Matrix));

    (ret_matrix->a_00) = n;
    (ret_matrix->a_01) = n;
    (ret_matrix->a_10) = n;
    (ret_matrix->a_11) = n;

    return ret_matrix;
}

Matrix* init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11) {
/*==================================================================================*/
    Matrix* ret_matrix = (Matrix*)::operator new (sizeof(Matrix));

    (ret_matrix->a_00) = a_00;
    (ret_matrix->a_01) = a_01;
    (ret_matrix->a_10) = a_10;
    (ret_matrix->a_11) = a_11;

    return ret_matrix;  

}


Matrix* matrix_mult(Matrix* A, Matrix* B) {
    Matrix* result = (Matrix*)::operator new (sizeof(Matrix));

    (result->a_00) = ((A->a_00) * (B->a_00) + (A->a_01)*(B->a_10));
    (result->a_01) = ((A->a_00) * (B->a_01) + (A->a_01)*(B->a_11));
    (result->a_10) = ((A->a_10) * (B->a_00) + (A->a_11)*(B->a_10));
    (result->a_11) = ((A->a_10) * (B->a_01) + (A->a_11)*(B->a_11));

    return result;
}

Matrix* matrix_expo(Matrix* base_matrix, unsigned int index) {
    Matrix* result;

    if (index == 0) {
        result = init_matrix(1);
    }
    else if (index == 1) {
        result = base_matrix;
    }
    else {
        Matrix* temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
        result = matrix_mult( matrix_expo(temp,2), matrix_expo(base_matrix,(index % 2)) );
    }
    return result;
}

unsigned long long fib_matrix_expo(unsigned int n) {

    unsigned long long result = 0;
    Matrix* base = init_matrix(1,1,1,0);
    if (n == 0) {
        result = 0;
    }
    else {
        base = matrix_expo(base,(n-1));
        result = (base->a_00);
    }
    return result;      
}

但是这段代码会导致值> = 3的分段错误。我觉得问题出在mult_matrix()函数上,但我无法找到它。请帮忙。

编辑: 已找到导致溢出的错误,但此处似乎还存在其他逻辑错误。特别是编辑的代码输出错误的值,并且连续输入(如1和2,3和4,5和6)的输出是相同的。 :(

编辑后的代码:

#include <cmath>
#include <iostream>

using namespace std;

typedef struct Matrix {
    unsigned long long a_00;
    unsigned long long a_01;
    unsigned long long a_10;
    unsigned long long a_11;
}Matrix;

Matrix* init_matrix(unsigned long long n);
Matrix* init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11);
Matrix* mult_matrix(Matrix* A, Matrix* B);      
Matrix* expo_matrix(Matrix* A,unsigned int n);
unsigned long long fib_matrix_expo(unsigned int n); 

int main() {

    unsigned int n;
    cin >> n;

    unsigned long long result = fib_matrix_expo(n);
    cout << result << endl;
    return 0;
}


Matrix* init_matrix(unsigned long long n) {
    Matrix* ret_matrix = (Matrix*)::operator new (sizeof(Matrix));

    (ret_matrix->a_00) = n;
    (ret_matrix->a_01) = n;
    (ret_matrix->a_10) = n;
    (ret_matrix->a_11) = n;

    return ret_matrix;
}

Matrix* init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11) {
/*==================================================================================*/
    Matrix* ret_matrix = (Matrix*)::operator new (sizeof(Matrix));

    (ret_matrix->a_00) = a_00;
    (ret_matrix->a_01) = a_01;
    (ret_matrix->a_10) = a_10;
    (ret_matrix->a_11) = a_11;

    return ret_matrix;  

}


Matrix* matrix_mult(Matrix* A, Matrix* B) {
    Matrix* result = (Matrix*)::operator new (sizeof(Matrix));

    (result->a_00) = ((A->a_00) * (B->a_00) + (A->a_01)*(B->a_10));
    (result->a_01) = ((A->a_00) * (B->a_01) + (A->a_01)*(B->a_11));
    (result->a_10) = ((A->a_10) * (B->a_00) + (A->a_11)*(B->a_10));
    (result->a_11) = ((A->a_10) * (B->a_01) + (A->a_11)*(B->a_11));

    return result;
}

Matrix* matrix_expo(Matrix* base_matrix, unsigned int index) {
    Matrix* result;

    if (index == 0) {
        result = init_matrix(1);
    }
    else if (index == 1) {
        result = base_matrix;
    }
    else {
        Matrix* temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
        result = matrix_mult(temp,temp);
        result = matrix_mult(result,matrix_expo(base_matrix,(index % 2)));
    }
    return result;
}

unsigned long long fib_matrix_expo(unsigned int n) {

    unsigned long long result = 0;
    Matrix* base = init_matrix(1,1,1,0);
    if (n == 0) {
        result = 0;
    }
    else {
        base = matrix_expo(base,(n-1));
        result = (base->a_00);
    }
    return result;      
}
编辑:这个bug也已经解决了。但正如Paul所指出的那样,它有很多内存泄漏。我将尝试在不使用手动动态内存分配的情况下实现它并重新发布它。然后按照n.m.的建议我将在使用构造函数并删除其他不必要的复杂功能后更新代码。当前工作代码:

编辑:没有内存泄漏的代码:

#include <cmath>
#include <iostream>

using namespace std;

struct Matrix {
    unsigned long long a_00;
    unsigned long long a_01;
    unsigned long long a_10;
    unsigned long long a_11;
};

Matrix init_matrix(unsigned long long n);
Matrix init_matrix(unsigned long long a_00, unsigned long long a_01,
                   unsigned long long a_10, unsigned long long a_11);
Matrix mult_matrix(const Matrix& A, const Matrix& B);      
Matrix expo_matrix(const Matrix& A,unsigned int n);
unsigned long long fib_matrix_expo(unsigned int n); 

int main() {

    unsigned int n;
    cin >> n;

    unsigned long long result = fib_matrix_expo(n);
    cout << result << endl;
    return 0;
}


Matrix init_matrix(unsigned long long n) {
    Matrix ret_matrix;

    ret_matrix.a_00 = n;
    ret_matrix.a_01 = n;
    ret_matrix.a_10 = n;
    ret_matrix.a_11 = n;

    return ret_matrix;
}

Matrix init_matrix(unsigned long long a_00, unsigned long long a_01,
                    unsigned long long a_10, unsigned long long a_11) {
/*==================================================================================*/
    Matrix ret_matrix;

    ret_matrix.a_00 = a_00;
    ret_matrix.a_01 = a_01;
    ret_matrix.a_10 = a_10;
    ret_matrix.a_11 = a_11;
    return ret_matrix;  
}


Matrix matrix_mult(const Matrix& A, const Matrix& B) {
    Matrix result;

    result.a_00 = ((A.a_00) * (B.a_00) + (A.a_01)*(B.a_10));
    result.a_01 = ((A.a_00) * (B.a_01) + (A.a_01)*(B.a_11));
    result.a_10 = ((A.a_10) * (B.a_00) + (A.a_11)*(B.a_10));
    result.a_11 = ((A.a_10) * (B.a_01) + (A.a_11)*(B.a_11));

    return result;
}

Matrix matrix_expo(const Matrix& base_matrix, unsigned int index) {
    Matrix result;

    if (index == 0) {
        result = init_matrix(1);
    }
    else if (index == 1) {
        result = base_matrix;
    }
    else {
        Matrix temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
        result = matrix_mult(temp,temp);
        if(index % 2 == 1) {
            result = matrix_mult(result,base_matrix);
        }
    }
    return result;
}

unsigned long long fib_matrix_expo(unsigned int n) {

    unsigned long long result = 0;
    Matrix base = init_matrix(1,1,1,0);
    if (n == 0) {
        result = 0;
    }
    else {
        base = matrix_expo(base,(n-1));
        result = base.a_00;
    }
    return result;      
}

2 个答案:

答案 0 :(得分:1)

由于此处的递归,matrix_expo函数中存在堆栈溢出

Matrix* temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
result = matrix_mult( matrix_expo(temp,2), matrix_expo(base_matrix,(index % 2)) );

让我们看看为什么

Matrix matrix_expo(Matrix base_matrix, unsigned int index) {
    Matrix result;

    if (index == 0) {
        result = init_matrix(1);
    }
    else if (index == 1) {
        result = base_matrix;
    }
    else {
        Matrix temp = matrix_expo(base_matrix,static_cast<unsigned int>(index/2));
        result = matrix_mult( matrix_expo(temp,2), matrix_expo(base_matrix,(index % 2)) );
    }
    return result;
}

如果index == 2,则始终到达matrix_expo(temp, 2),这会导致无限递归。

其他一些问题与new有关,而且从未使用过delete,这实际上失去了delete

的机会
base = matrix_expo(base,(n-1));

因为base可以使用new分配,并且你重新指向指向new已分配内存的基指针。

我说可以使用new分配,因为这行

result = base_matrix;

如果是前面提到的情况,那么你将返回base它自己的情况,但在任何其他情况下,此函数中result的其他任务将使用new分配一个将返回一个指向最初分配的内存的指针,因此如果你使用delete运算符释放这个内存,你有机会双倍释放。

答案 1 :(得分:1)

这是使用Matrix的C ++实现。不幸的是,我不知道足够多的矩阵来指出&#34;&#34;&#34;您原始代码的问题;简单地用类重写它似乎已经摆脱了问题。我无法解释你的expo函数内部工作,所以我把它写成一个简单的循环。

使用类意味着所有操作都是&#34; on&#34;仅限单个矩阵;无需再制作多份副本! (除1,1,1,0函数中的expo帮助器外; C ++将自动删除该函数末尾的temp1矩阵。)

默认情况下会使用1,1,1,0初始化新的Matrix,因此可以删除initexpo中的fib_matrix_expo

这也意味着您可以轻松扩展Matrix类以执行其他功能。

#include <cmath>
#include <iostream>

using namespace std;

class Matrix {
    unsigned long long a_00;
    unsigned long long a_01;
    unsigned long long a_10;
    unsigned long long a_11;

public:
    Matrix();
    void init(unsigned long long n);
    void mult(Matrix* B);
    void expo (unsigned int n);
    unsigned long long value ()
    {
        return a_00;
    }
};

unsigned long long fib_matrix_expo(unsigned int n); 

int main() {

    unsigned int n;
    cin >> n;

    unsigned long long result = fib_matrix_expo(n);
    cout << result << endl;
    return 0;
}

/* In this, and all other class functions, the specifier 'this->' is
   not required. Per definition, all variables from the class are
   immediately accessible. However, including 'this->..' makes it
   clear you *are* modifying the class variables, and not local ones
   with the same name */
Matrix::Matrix () {
    this->a_00 = 1;
    this->a_01 = 1;
    this->a_10 = 1;
    this->a_11 = 0;
}


void Matrix::init (unsigned long long n) {
    this->a_00 = n;
    this->a_01 = n;
    this->a_10 = n;
    this->a_11 = n;
}

void Matrix::mult(Matrix* B)
{
    unsigned long long t00,t01,t10,t11;

    t00 = this->a_00 * B->a_00 + this->a_01 * B->a_10;
    t01 = this->a_00 * B->a_01 + this->a_01 * B->a_11;
    t10 = this->a_10 * B->a_00 + this->a_11 * B->a_10;
    t11 = this->a_10 * B->a_01 + this->a_11 * B->a_11;

    this->a_00 = t00;
    this->a_01 = t01;
    this->a_10 = t10;
    this->a_11 = t11;

    // printf ("%llu %llu %llu %llu\n", a_00, a_01, a_10, a_11);
}

void Matrix::expo(unsigned int index)
{
    if (index == 0)
    {
        this->init(1);
        return;
    }
    if (index == 1)
    {
        return;
    }

    Matrix temp1;
    // temp1 will initialize itself with (1,1,1,0),
    // nothing more needed
    while (--index > 0)
    {
        this->mult (&temp1);
    }
}

unsigned long long fib_matrix_expo (unsigned int n)
{
    Matrix base;
    if (n == 0)
        return 0;

    // No need to initialize to the default values, as this
    // is done in the default constructor.
    base.expo(n-1);
    return base.value();
    // Since 'base' is a locally created class object, you
    // do not need to delete it.
}

建设性批评受到欢迎,因为我不是每天的C ++程序员;)