标准c重写QR分解算法,用来计算线性或超定方程组,计算结果和matlab一致

对上版一版本的代码做了内存优化,修正了非必要的内存分配,计算结果与matlab的qr命令运算结果一致。请自行按main中提供的自己自行修改数据,进行验证。

#include <math.h>
#include <stdlib.h>
#include <memory.h>
#include <iostream>

using namespace std;

double dot(double * a, double * b, int len){
    double result = 0;
    for (int i = 0; i<len; i++)
        result += a[i] * b[i];
    return result;
}

//列向量与行向量乘法
void mulvector(double * a, double * b, int len, double cof, double * c){
    for (int i = 0; i < len; ++i)
        for (int j = 0; j < len; ++j)
            c[i * len + j] = cof * a[i] * b[j];
    return;
}


//矩阵与矩阵,矩阵与向量相乘
bool mulmatrix(double * a, int ar, int ac, double * b, int br, int bc, double  * c)
{
    //c为输出矩阵
    if (ac != br)
        return false;
    else
    {
        for (int i = 0; i < ar; ++i)
        {
            for (int j = 0; j < bc; ++j)
            {
                double sum = 0;
                for (int k = 0; k < ac; ++k)
                    sum += a[i * ac + k] * b[k * bc + j];

                c[i*bc + j] = sum;
            }
        }
        return true;
    }
}

void transpose(double * coef, int row, int col, double * trans_coef)
{
    for (int r = 0; r < row; ++r)
        for (int c = 0; c < col; ++c)
            trans_coef[c * row + r] = coef[r * col + c];
}


void houseQR(double * A, int xsize, int ysize, double * Q, double * R)
{
    double * tempA = (double *)calloc(xsize * ysize, sizeof(double));
    memcpy(tempA, A, sizeof(double) * xsize * ysize);   //对A先复制一份
    int szA_rows = ysize;
    int szA_cols = xsize;

    int bound = ysize > xsize ? xsize : xsize - 1;

    double * temp1 = (double *)malloc(ysize * ysize * sizeof(double));

扫描二维码关注公众号,回复: 2943552 查看本文章

    double * tempQ = (double *)malloc(ysize * ysize * sizeof(double));

    double * tempR = (double *)malloc(ysize * xsize * sizeof(double));

    //对H的每一列进行处理
    for (int k = 0; k < bound; ++k)
    {
        double * a = (double *)calloc(ysize - k, sizeof(double));
        double sum = 0;
        for (int i = 0; i < ysize - k; ++i)
        {
            a[i] = tempA[i * szA_cols];
            sum += a[i] * a[i];
        }

        if (a[0] >= 0)
            a[0] += sqrt(sum);
        else
            a[0] -= sqrt(sum);

        double cof = -2. / dot(a, a, ysize - k);
        //计算wwT
        double * hw = (double *)calloc((ysize - k) * (ysize - k), sizeof(double));

        mulvector(a, a, ysize - k, cof, hw);
        //计算wwt+I
        for (int i = 0; i < ysize - k; ++i)
            hw[i * (ysize - k) + i] += 1.;

        //hw * A
        //到最后一列就不用生成tempA了,因为这次运行完就跳出循环了
        if (k < xsize - 1)
        {
            double * temp = (double *)calloc((ysize - k) * (xsize - k), sizeof(double));
            mulmatrix(hw, ysize - k, ysize - k, tempA, szA_rows, szA_cols, temp);

            szA_rows = ysize - k - 1;
            szA_cols = xsize - k - 1;

            tempA = (double *)realloc(tempA, sizeof(double) * szA_rows * szA_cols);


            for (int i = 0; i < szA_rows; ++i)
                for (int j = 0; j < szA_cols; ++j)
                    tempA[i * szA_cols + j] = temp[(i + 1) * (xsize - k) + (j + 1)];

            free(temp); temp = NULL;
        }

        if (k == 0)
        {
            memcpy(Q, hw, sizeof(double) * ysize * ysize);
            mulmatrix(hw, ysize, ysize, A, ysize, xsize, R);
        }
        else
        {
            memset(temp1, 0, ysize * ysize * sizeof(double));  //temp1使用前必须清0

            for (int i = 0; i < ysize; ++i)
                temp1[i * ysize + i] = 1.;    //先把temp变成单位阵
            for (int i = k; i < ysize; ++i)
                for (int j = k; j < ysize; ++j)
                    temp1[i * ysize + j] = hw[(i - k) * (ysize - k) + (j - k)];


            ////////////////算R
            mulmatrix(temp1, ysize, ysize, R, ysize, xsize, tempR);

            memcpy(R, tempR, sizeof(double) * ysize * xsize);
            ////////////////////算R

            mulmatrix(Q, ysize, ysize, temp1, ysize, ysize, tempQ);

            memcpy(Q, tempQ, sizeof(double) * ysize * ysize);


        }
        free(hw); hw = NULL;
        free(a); a = NULL;
    }

    for (int i = 0; i < ysize; ++i)
        for (int j = 0; j < xsize; ++j)
            if (j < i)
                R[i * xsize + j] = 0.;

    free(temp1); temp1 = NULL;

    free(tempQ); tempQ = NULL;

    free(tempR); tempR = NULL;

    free(tempA); tempA = NULL;
}

void main()
{
    double A[] = {
        -49.2027, -97.9266, 75.9276, -98.0746, 106.3013, 109.4175, 28.1809, 170.9210,
        -22.1010, -35.9840, 29.8188, -44.8198, 85.8362, 145.4886, -8.6558, 110.0333,
        29.7531, -59.8524, -80.0797, -206.6228, -43.3985, -53.0652, -20.5665, 26.1748,
        -16.5143, -122.0781, 70.8578, 21.7132, 56.3361, 184.9878, -93.7156, -73.7575,
        63.2524, 17.5248, -95.7341, 187.6219, 18.6626, 11.4521, -54.7813, 16.9025,
        49.9103, -232.1722, 136.1783, -9.0688, 155.5447, 179.5115, -94.4528, -52.9377,
        -44.5809, 36.2338, -202.5602, -35.4398, -74.8771, 86.0590, 69.0331, -28.7896,
        54.1079, 154.8040, 1.4695, -76.6472, 45.5199, -137.4193, -19.1431, -116.1613
    };

    /*
    double A[] = {
    164.1783, -38.9102, 24.8812, -36.9874, 103.4167, 57.4929, -39.8941, 26.4760,
    68.4810, 18.7745, -79.7541, 0.5480, 31.0084, -72.5418, -23.8719, -15.2310,
    -5.9808, 95.1554, -28.7140, -74.9151, 329.3934, 29.9765, -12.5489, 91.0916,
    -108.5666, 105.5885, 95.9353, 80.6216, -50.3015, -60.3160, -17.6538, 73.9389,
    -67.5289, 78.6109, -155.7623, 34.5077, 62.9115, 96.4753, 149.7857, 62.7200,
    38.6026, 101.4746, -50.3931, -170.5524, 50.2047, -125.8341, 36.6699, -65.1695,
    69.6143, -27.2240, 16.5026, 120.6058, 96.6424, -46.2672, 120.7360, -175.1475,
    123.7181, 67.2493, -91.6087, 157.7219, 81.6495, -67.1533, -51.7428, -66.7180
    };
    */

    double * Q = (double *)calloc(8 * 8, sizeof(double));  
    double * R = (double *)calloc(8 * 8, sizeof(double));  
    houseQR(A, 8, 8, Q, R);

    for (int i = 0; i < 8; ++i)
    {
        for (int j = 0; j < 8; ++j)
            cout << R[i * 8 + j] << " ";
        cout << endl;
    }


    free(Q); Q = NULL;
    free(R); R = NULL;
}

猜你喜欢

转载自blog.csdn.net/cos828/article/details/82149872