⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 homework1.c

📁 刚才邮箱写错了 幂法反幂法程序作业 带LU分解子程序 DOLITTLE分解法等
💻 C
字号:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>

#define MAXLOOPS	2000	//最大迭代次数
#define AU 			2		//上半带宽
#define AD 			2		//下半带宽
#define AM 			5		//压缩矩阵高度
#define AN 			501		//压缩矩阵宽度
#define ER 			1e-12	//精度水平
#define bb 			0.16
#define cc 			-0.064
#define GetSgn(a)	((a) > 0 ? 1 : ((a) < 0 ? -1 : 0))									//符号函数
#define max3(a, b, c)	(((a) > (b) ? (a) : (b)) > (c) ? ((a) > (b) ? (a) : (b)) : (c))	//求三个数的最大值
#define min2(a, b)	((a) < (b) ? (a) : (b))												//求两个数的最小值

void main()
{
	int PowERMethod(double *pc, int length, int endLoops, double *resultOut, int type);
	int MaxNumInVector(double *pIn, int length);
	void AMultiY(double *aii, double *inY, double *outU, int length);
	void UnitaryVector(double *pVectorIn, double *pVectorOut, int length, double numbER);
	void Doolittle(double *c, double *b, double *xOut, int length, int s, int r);
	double LU(double *z, int length, int s, int r, int flag);
	
	int true=1;
	int false=0;
	int i, j, loops;
	double c[AN*AM];	//用c压缩存储带状矩阵A
	double r1, rs, r501, d, mk, cond, det;
	double m[39];
	double tempC[AN*AM];
	
	//把带状矩阵A压缩存储为C
	for (i = 0; i < AN; i++)
	{
		c[0 * AN + i] = cc;
		c[1 * AN + i] = bb;
		c[2 * AN + i] = ( 1.64 - 0.024 * ( i + 1 ) ) * sin( 0.2 * ( i + 1 ) ) - 0.64 * exp( 0.1 / ( i + 1 ) );
		c[3 * AN + i] = bb;
		c[4 * AN + i] = cc;
	}
	c[ 0 ] = 0;
	c[ 1 ] = 0;
	c[ 1 * AN + 0 ] = 0;
	c[ 3 * AN + AN - 1 ] = 0;
	c[ 4 * AN + AN - 1 ] = 0;
	c[ 4 * AN + AN - 2 ] = 0;
	
	//幂法求最小特征值r1
	for (i = 0; i < AN * AM; i++)
	{
		tempC[i] = c[i];
	}
	loops = PowERMethod(tempC, AN, MAXLOOPS, &r1, true);
	printf("最小特征值r1\t=%1.11e 迭代次数:%d\n", r1, loops);
	
	//幂法求最大特征值,原点平移r501
	for (i = 0; i < AN * AM; i++)
	{
		tempC[i] = c[i];
		if (i >= AU * AN && i < (AU + 1) * AN)
		{
			tempC[i] -= r1;
		}
	}
	loops = PowERMethod(tempC, AN, MAXLOOPS, &r501, true);
	r501 += r1;
	printf("最大特征值r501\t= %1.11e 迭代次数: %d\n", r501, loops);
	
	//反幂法求模最小特征值rs
	for (i = 0; i < AN * AM; i++)
	{
		tempC[i] = c[i];
	}
	LU(tempC, AN, AU, AD, false);
	loops = PowERMethod(tempC, AN, MAXLOOPS, &rs, false);
	printf("模最小特征值rs\t=%1.11e 迭代次数: %d\n", rs, loops);
		
	//用原点平移的反幂法求rik
	d = (r501 - r1) / 40;
	for (j = 1; j < 40; j++)
	{
		mk = r1 + j * d;
		for (i = 0; i < AN * AM; i++)
		{
			tempC[i] = c[i];
			if (i >= AU * AN && i < (AU + 1) * AN)
			{
				tempC[i] -= mk;
			}
		}
		LU(tempC, AN, AU, AD, false);
		loops = PowERMethod(tempC, AN, MAXLOOPS, &m[j - 1], false);
		m[j - 1] += mk;
		printf("(%d)\t最接近%1.11e的特征值为%1.11e\t迭代次数: %d\n", j, mk, m[j - 1], loops);
	}
	
	//求谱范数和行列式的值
	for (i = 0; i < AN * AM; i++)
	{
		tempC[i] = c[i];
	}
	cond = fabs(r1/rs);
	det = LU(tempC, AN, AU, AD, true);
	printf("A的条件数cond(A)2 = %1.11e\n", cond);
	printf("A的行列式detA = %1.11e\n", det);
}

//幂法求最大特征值; type = true幂法; type = false反幂法
int PowERMethod(double *pc, int length, int endLoops, double *resultOut, int type)
{
	double y[AN];
	double u[AN];
	double h;
	double b1=0; 
	double b2;
	int i, k, t; 
	double aii[AN];
	for (i = 0; i < length; i++)
	{
		aii[i] = pc[AU * length + i];
	}	
	//u0设置初值
	for (i = 0; i < length; i++)
	{
		u[i] = 1;
	}
	
	for ( t = 1; t <= endLoops; t++)
	{
		k = MaxNumInVector(u, length);
		h = u[k];
		UnitaryVector(u, y, length, 1/fabs(h));

		if (type)
		{
			AMultiY(aii, y, u, length);
		}
		else
		{	
			Doolittle(pc, y, u, length, AU, AD);  	//y的值会被改变
		}

		b2 = GetSgn(h) * u[k];
		*resultOut = b2;
		if (!type)
		{
			*resultOut = 1 / b2;
		}
		
		if (t >1 && (fabs(b2 - b1) / fabs(b2) <= ER))
		{
			break;
		}
		b1 = b2;
	}
	return t;
}

//求向量中模最大的分量,返回分量的下标
int MaxNumInVector(double *pIn, int length)
{
	int i, k;
	double temp = pIn[0];
	k = 0;
	for (i = 0; i < length; i++)
	{
		if (fabs(pIn[i]) > fabs(temp))
		{
			temp = pIn[i];
			k = i;
		}
	}
	return k;
}

//矩阵A乘以向量y,结果保存在u中
void AMultiY(double *aii, double *inY, double *outU, int length)
{
	int i, j;
	for (i = 0; i < length; i++)
	{
		outU[i] = aii[i] * inY[i];
		j = i;               
		if (j - AD >= 0)
			outU[i] += cc * inY[j - AD];
		if (j - AD + 1 >= 0)
			outU[i] += bb * inY[j - AD + 1];	
		if (j + AU < length)
			outU[i] += cc * inY[j + AU];
		if (j + AU - 1 < length)
			outU[i] += bb * inY[j + AU - 1];
	}
}

//向量数乘,用于向量u归一化
void UnitaryVector(double *pVectorIn, double *pVectorOut, int length, double numbER)
{
	int i;
	for (i = 0; i < length; i++)
	{
		pVectorOut[i] = pVectorIn[i] * numbER;
	}
}

//杜利特尔分解方法求方程组的解,结果储存在b中
void Doolittle(double *c, double *b, double *xOut, int length, int s, int r)
{
	int i, t, max, min;
	double temp;
	for (i = 2; i <= length; i++)
	{
		temp = 0;
		max = max3(1, 1, i - r);
		for (t = max; t <= (i - 1); t++)
		{
			temp += ( c[(i - t + s) * length + t - 1] * b[t - 1] );
		}
		b[i - 1] = b[i - 1] - temp;
	}

	xOut[length - 1] = b[length - 1] / c[s * length + length - 1];
	for (i = length - 1; i >= 1; i--)
	{
		temp = 0;
		min = min2(i + s, length);
		for (t = i + 1; t <= min; t++)
		{
			temp += c[(i - t + s) * length + t - 1] * xOut[t - 1];
		}
		xOut[i - 1] = (b[i - 1] - temp) / c[s * length + i - 1];
	}
}

//LU分解,如果flag=true,返回计算的行列式值
double LU(double *z, int length, int s, int r, int flag)
{
	int i, j, k, t, max, min;
	double temp;
	for (k = 1; k <= length; k++)
	{
		min = min2(k + s, length);
		for (j = k; j <= min; j++)
		{
			temp = 0;
			max = max3(1, k - r, j - s);
			for (t = max; t <= (k - 1); t++)
			{
				temp += ( z[(k - t + s) * length + t - 1] * z[(t - j + s) * length + j - 1] );
			}
			z[(k - j + s) * length + j - 1] = z[(k - j + s) * length + j - 1] - temp;
		}
		min = min2(k + r, length);
		for (i = k + 1; i <= min && k < length; i++)
		{
			temp = 0;
			max = max3(1, i - r, k - s);
			for (t = max; t <= (k - 1); t++)
			{
				temp += ( z[(i - t + s) * length + t - 1] * z[(t - k + s) * length + k - 1] );
			}
			z[(i - k + s) * length + k - 1] = (z[(i - k + s) * length + k - 1] - temp) / z[s * length + k - 1];
		}
	}

	if (flag)
	{
		temp =	1;
		for (i = 0; i < length; i ++)
		{
			temp *= z[s * length + i];
		}
		return temp;
	}
	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -