对上版一版本的代码做了内存优化,修正了非必要的内存分配,计算结果与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));
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;
}