C中的Cholesky分解失败

时间:2015-11-09 15:49:03

标签: c arrays pointers

我对c很新,并希望根据维基百科的伪代码实现cholesky分解。 这是必需的,ram是动态分配的。

我使用以下示例矩阵尝试了我的代码:

 4.000  2.000  0.000  0.000
 2.000  5.000  2.000  0.000
 0.000  2.000 10.000  3.000
 0.000  0.000  3.000  2.000

应导致:

2.000 0.000 0.000 0.000
1.000 2.000 0.000 0.000
0.000 1.000 3.000 0.000
0.000 0.000 1.000 1.000

但是回来了。

4.000 2.000 0.000  0.000 
0.000 5.000 2.000  0.000 
0.000 0.000 10.000 3.000 
0.000 0.000 0.000  2.000

我猜我在使用指针时遇到了一些误解。我试图根据this link动态分配。

有人能告诉我,为什么正确的值没有写入我的矩阵? 这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int Cholesky(int n, double **A){
    double sum;
    sum = 0.0f;
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < i; j++)
        {
            for(int k = 0; k < j-1; k++)
            {
                sum = sum - A[i][k]*A[j][k];
            }
            if(i > j)
            {
                A[i][j] = sum / A[j][j];
            } else
            {
                if(sum > 0)
                {
                    A[i][i] = sqrt(sum);
                } else {
                    printf("Die Matrix ist nicht symetrisch positiv\n");
                    return -1;
                }
            }
        }
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)
            printf("%.5f ", A[i][j]);
            printf("\n");
    }

}

int main(){
    int n = 4;
    double ** matrix;

    double test[4][4] = {{4.0f,2.0f,0.0f,0.0f},{2.0f,5.0f,2.0f,0.0f},{0.0f,2.0f,10.0f, 3.0f},{0.0f,0.0f,3.0f,2.0f}};

    /* Speicher reservieren für die int-Zeiger (=zeile) */
    matrix = malloc(n * sizeof(double *));
    if(NULL == matrix) {
       printf("Kein virtueller RAM mehr vorhanden ... !");
       return -1;
    }
    /* jetzt noch Speicher reservieren für die einzelnen Spalten
     * der i-ten Zeile */
    for(int i = 0; i < n; i++) {
        matrix[i] = malloc(n * sizeof(double));
        if(NULL == matrix[i]) {
            printf("Kein Speicher mehr fuer Zeile %d\n",i);
            return -1;
        }
    }
    /* mit beliebigen Werten initialisieren */
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            matrix[i][j] = test[i][j];

    /* Inhalt der Matrix entsprechend ausgeben */
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)
            printf("%.5f ", matrix[i][j]);
            printf("\n");
    }

    Cholesky(n, matrix);

    /* Spalten der i-ten Zeile freigeben */
    for(int i = 0; i < n; i++)
        free(matrix[i]);
    /* Jetzt können die leeren Zeilen freigegeben werden. */
    free(matrix);
    int x;
    scanf("%d", x);
    return 0;
}

4 个答案:

答案 0 :(得分:1)

您动态分配的矩阵是正确的,也是指针的使用。

正确的值不会写入矩阵,因为您用于cholesky分解的算法是错误的。您可以在此处找到正确的算法:

http://www2.denizyuret.com/bib/press/www.library.cornell.edu/nr/bookcpdf/c2-9.pdf

您的函数仅在此指令处修改矩阵:

if (i > j) A[i][j] = sum / A[j][j]; 

表示对角线下方的元素归零,如帖子所示。

4.000 2.000 0.000  0.000 
0.000 5.000 2.000  0.000 
0.000 0.000 10.000 3.000 
0.000 0.000 0.000  2.000

答案 1 :(得分:0)

在调用Cholesky()之前打印矩阵,这就是打印原始矩阵的原因。

答案 2 :(得分:-1)

Cholesky算法是否就地工作?

尝试将此作为您功能的基础

 for (int i=0; i<n; i++) {
        chol[i][i] = A[i][i];
        for (int k=0; k<i; k++)
            chol[i][i] -= chol[k][i]*chol[k][i];
        chol[i][i] = sqrt(chol[i][i]);
        for (int j=i+1; j<n; j++) {
            chol[i][j] = A[i][j];
            for (k=0; k<i; k++)
                chol[i][j] -= chol[k][i]*chol[k][j];
            chol[i][j] /= chol[i][i];
        }
 }

答案 3 :(得分:-1)

所以例如,因为我讨厌数组的数组:

#include <malloc.h>
#include <math.h>

#define idx(A,i,j) A[i*n+j]

void Cholesky(int n, double *A)
{
    double *chol = (double *)calloc(sizeof(double) * n * n, 1);

    for (int i = 0; i<n; i++) {
        idx(chol, i, i) = idx(A, i, i);
        for (int k = 0; k<i; k++)
            idx(chol, i, i) -= idx(chol, k, i) * idx(chol, k, i);
        idx(chol, i, i) = sqrt(idx(chol, i, i));
        for (int j = i + 1; j<n; j++) {
            idx(chol, i, j) = idx(A, i, j);
            for (int k = 0; k<i; k++)
                idx(chol, i, j) -= idx(chol, k, i) * idx(chol, k, j);
            idx(chol, i, j) /= idx(chol, i, i);
        }
    }

    memcpy(A, chol, sizeof(double) * n * n);
    free(chol);
}

int main()
{
    double test[] = { 
        4.0f, 2.0f, 0.0f, 0.0f,
        2.0f, 5.0f, 2.0f, 0.0f,
        0.0f, 2.0f, 10.0f, 3.0f,
        0.0f, 0.0f, 3.0f, 2.0f };

    Cholesky(4, test);
}