【C++ 程序】 TVJ Matrix Laboratory (v 1.1)

简介

这是一个用 Visual C++做的关于线性代数(尤其是与矩阵相关的计算)的小软件。
图标
版本
系统要求:Windows

应用程序(exe)下载

链接:https://download.csdn.net/download/weixin_50012998/13120843

Help

What is new in v 1.1

  1. 修改好了 v 1.0 中的bug
  2. 增加了求逆矩阵的功能
  3. 增加了帮助(Help)选项

功能选择

输入功能模式
1求行列式
2求转置矩阵
3求逆矩阵
4矩阵乘法
5解线性方程组
其他结束程序

输入要求

  • 行列式:每行输入行列式的一行,输完一行回车回车后输入下一行。当最后一次换行后输出。
  • 转置矩阵:每行输入行列式的一行,输完一行回车回车后输入下一行。当最后一次换行后输入"end"后输出。
  • 求逆矩阵:每行输入行列式的一行,输完一行回车回车后输入下一行。当最后一次换行后输出。
  • 矩阵乘法:先输入矩阵A。每行输入行列式的一行,输完一行回车回车后输入下一行。当最后一次换行后输入"end"后开始输入矩阵B。每行输入行列式的一行,输完一行回车回车后输入下一行。当最后一次换行后输入"end"后输出。
  • 解线性方程组:输入线性方程组的增广矩阵(且方程数必须等于未知数数量),当最后一次换行(自动识别方程数与未知数数量相等)后输出。
  • 结束程序:按任意键关闭。

新功能图片示例

1
2

其他图片示例见我的博客 【C++ 程序】 TVJ Matrix Laboratory (v 1.0)中的输出示例。

程序

Source.cpp

#include <iostream>
#include <Windows.h>
#include <conio.h>
#include "Cinvec.h"
#include "Det.h"
#include "Formula.h"
#include "Inverse.h"
#include "Multiply.h"
#include "Transpose.h"
using namespace std;

void set_size()
{
	CONSOLE_FONT_INFOEX cfi;
	cfi.cbSize = sizeof cfi;
	cfi.nFont = 0;
	cfi.dwFontSize.X = 0; // the width of the character
	cfi.dwFontSize.Y = 22;// the height of the character
	cfi.FontFamily = FF_DONTCARE;
	cfi.FontWeight = FW_NORMAL; // weight
	wcscpy_s(cfi.FaceName, L"Raster"); // set font, this place is the Raster font
	SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), FALSE, &cfi);
}

void set_green()
{
	// set the colour green
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);
}

void set_yellow()
{
	// set the colour yellow
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
}

void set_white()
{
	// set the colour white
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}

int main(int argc, char** argv)
{
	set_size();
	set_green();
	cursor("hide");
	cout << "TVJ Matrix Laboratory (v 1.1)\nTeddy van Jerry\n==============================\n" << endl;
	MessageBox(NULL, L"This is TVJ Matrix Laboratory (v 1.1)\nDesigned by Teddy van Jerry\n2020.11\n\nPlease make sure that your input is legal!",
		L"Information", MB_ICONINFORMATION);
	int choice_help = MessageBox(NULL, L"Want to see HELP?", L"TVJ Matrix Laboratory", MB_YESNO | MB_ICONINFORMATION);
	if (choice_help == IDYES)
	{
		// go to my CSDN blog
		ShellExecute(NULL, L"open", L"explorer.exe", L"https://blog.csdn.net/weixin_50012998/article/details/109753175", NULL, SW_SHOW);
	}
	while (1)
	{
		/*
		cout << "Please choose the mode:" << endl;
		cout << "1. Determinant" << endl;
		cout << "2. Transpose" << endl;
		cout << "3. Inverse" << endl;
		cout << "4. Multiply" << endl;
		cout << "5. Solve linear formulas" << endl;
		cout << "Others: Exit" << endl;
		*/

		cursor("hide");
		MessageBox(NULL, L"Please choose the mode:\n1. Determinant\n2. Transpose\n3. Inverse\n4. Multiply\n5. Solve linear formulas\nOthers: Exit",
			L"TVJ Matrix Laboratory", MB_ICONINFORMATION);
		char n = _getch();
		cout << "\r";
		
		switch (n)
		{
		case '1':
			set_yellow();
			cout << "MODE 1: Determinant" << endl;
			set_white();
			cursor("show");
			det();
			break;
		case '2':
			set_yellow();
			cout << "MODE 2: Transpose" << endl;
			set_white();
			cursor("show");
			transpose();
			break;
		case '3':
			set_yellow();
			cout << "MODE 3: Inverse" << endl;
			set_white();
			cursor("show");
			inverse();
			break;
		case '4':
			set_yellow();
			cout << "MODE 4: Multiply" << endl;
			set_white();
			cursor("show");
			multiply();
			break;
		case '5':
			set_yellow();
			cout << "MODE 5: Solve linear formulas" << endl;
			set_white();
			cursor("show");
			formula();
			break;
		default:
			set_white();
			cout << "ALL RIGHTS RESERVED (C) 2020 Teddy van Jerry" << endl;
			cout << "\n-----------------------------------------------------------------\nPress any key to exit." << endl;
			n = _getch();
			return 0; // exit
		}
	}
	return 0;
}

Algebraic cofactor.h

#ifndef _ALGEBRAIC_COFACTOR_
#define _ALGEBRAIC_COFACTOR_
#include "Det.h"

double exclude(std::deque<std::deque<double>> deq, int i, int j)
{
	int Sign = ((i + j) % 2 == 0) ? 1 : -1;
	std::deque<std::deque<double>> temp = deq;
	for (int k = i - 1; k >= 0; k--)
	{
		for (int t = 0; t != temp[0].size(); t++)
		{
			temp[k + 1][t] = temp[k][t];
		}
	}
	temp.pop_front();
	for (int t = j - 1; t >= 0; t--)
	{
		for (int k = 0; k != temp.size(); k++)
		{
			temp[k][t + 1] = temp[k][t];
			if (t == 0)temp[k].pop_front();
		}
	}
	if (j == 0)
	{
		for (int k = 0; k != temp.size(); k++)
		{
			temp[k].pop_front();
		}
	}
	return (Sign * det_is(temp) == -0) ? 0 : Sign * det_is(temp);
}

#endif // !_ALGEBRAIC_COFACTOR_

Cinvec.h

#ifndef _CINVEC_
#define _CINVEC_
#include <iostream>
#include <vector>
#include <string>
#include <sstream> // std::istringstream
#include <deque>
#include <conio.h>

int index[] = { 0,0,0 }; // define

std::vector<double> cinvec_d(std::string cin_d, int& N)
{
	getline(std::cin, cin_d);
	std::vector<double> vd;
	if (cin_d == "end")
	{
		N = 1;
		return vd;
	}
	std::istringstream is(cin_d);
	double i;
	while (is >> i)
		vd.push_back(i);
	return vd;
}

std::deque<double> cindeq_d(std::string cin_d, int& N)
{
	getline(std::cin, cin_d);
	std::deque<double> vd;
	if (cin_d == "end")
	{
		N = 1;
		return vd;
	}
	std::istringstream is(cin_d);
	double i;
	while (is >> i)
		vd.push_back(i);
	return vd;
}

void cinvec_s(std::deque<std::deque<double>>& det)
{
	unsigned n = 0;
	std::string str;
	// input
	while (1)
	{
		getline(std::cin, str);
		std::istringstream is(str);
		std::deque<double> row;
		double i;
		while (is >> i)
			row.push_back(i);
		if (!row.empty())
		{
			det.push_back(row);
			n = (row.size() > n) ? row.size() : n;
			if (det.size() >= n) break;
		}
	}
}

#endif // !_CINVEC_

Cursor.h

#ifndef _CURSOR_HS_
#define _CURSOR_HS_
#include <Windows.h>
#include <string>

void cursor(std::string str)
{
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cci;

	for (auto& c : str)
		c = tolower(c);

	if (str == "hide")
	{
		// hide the cursor
		GetConsoleCursorInfo(hOut, &cci);
		cci.bVisible = FALSE;
		SetConsoleCursorInfo(hOut, &cci);
	}
	else if (str == "show")
	{
		// show the cursor
		GetConsoleCursorInfo(hOut, &cci);
		cci.bVisible = TRUE;
		SetConsoleCursorInfo(hOut, &cci);
	}
}

#endif // !_CURSOR_

Det.h

#ifndef _DET_
#define _DET_
#include <deque>

double sign = 1;

void change_sequence(unsigned& n, std::deque<std::deque<double>>& d)
{
//  int have_or_not = 0; // to indicate if there is none-zero number in the first column
	if (d[0][0] == 0)
	{
		for (unsigned i = 1; i != n; i++)
		{
			if (d[i][0] != 0)
			{
				for (int j = 0; j != n; j++)
					std::swap(d[i][j], d[0][j]); // swap lines
				sign = -sign;
				break;
			}
		}
	}
	if (d[0][0] == 0) // if none of them is not zero
	{
		n = 1;
		d = { {0} };
	}
}

void shrink(unsigned& n, std::deque<std::deque<double>>& d)
{
	if (n != 1 && n != 2)
	{
		for (unsigned i = 1; i != n; i++)
			for (unsigned j = n - 1; j != 0; j--)
				d[i][j] -= d[0][j] * d[i][0] / d[0][0];
		sign *= d[0][0];
		for (unsigned i = 1; i != n; i++)
			d[i].pop_front();
		d.pop_front();
		n--;
	}
}

double det_is(std::deque<std::deque<double>> d)
{
	unsigned n = d.size();
	double ret = 0;
	while (n > 2)
	{
		change_sequence(n, d);
		shrink(n, d);
	}
	if (n == 1)
	{
		ret = sign * d[0][0];
		sign = 1;
	}
	else
	{
		ret = sign * (d[0][0] * d[1][1] - d[0][1] * d[1][0]);
		sign = 1;
	}
	return ret;
}

void det()
{
	std::cout << "Please input a determinant:\n" << std::endl;
	std::deque<std::deque<double>> det;
	cinvec_s(det);
	std::cout << "\n-----------------------------------------------------------------\n" << std::endl;
	std::cout << "det = " << ((det_is(det) != -0) ? det_is(det) : 0) << std::endl;
	std::cout << "\n=================================================================\n" << std::endl;
	sign = 1;
}

#endif // !_DET_

Formula.h

#ifndef _FORMULA_
#define _FORMULA_
#include "Cinvec.h"
#include "Fraction.h"
#include "Cursor.h"
#include <Windows.h>

void formula()
{
	int num;
	unsigned m = 0;
	std::deque<std::deque<double>> mat;
	std::deque<std::deque<std::deque<double>>> D;

	// instruction
	std::cout << "Please input in this sequence:\n"
		<< "a_11 * x_1 + a_12 * x_2 + ... + a_1n * x_n = b_1\n"
		<< "a_21 * x_1 + a_22 * x_2 + ... + a_2n * x_n = b_2\n"
		<< "...\n"
		<< "a_n1 * x_1 + a_n2 * x_2 + ... + a_nn * x_n = b_n"
		<< "\n" << std::endl;

	// input
	while (1)
	{
		std::deque<double> row;
		while (std::cin >> num)
		{
			row.push_back(num);
			if (getchar() == '\n') break;
		}
		mat.push_back(row);
		m = (row.size() > m) ? row.size() : m;
		if (mat.size() >= m - 1) break;
	}

	for (unsigned i = 0; i < m; i++)
	{
		std::deque<std::deque<double>> temp = mat; // D[m - 1][m]
		for (unsigned j = 0; j != m - 1; j++)
		{
			if (i) temp[j][i - 1] = mat[j][m - 1];
			temp[j].pop_back();
		}
		D.push_back(temp);
	}

	cursor("hide");

	// calculate & print
	double D0 = det_is(D[0]);
	if (D0 != 0)
	{
		std::cout << "\n-----------------------------------------------------------------\n"
			<< "By default you view the solution in the FRACTION form.\n"
			<< "You can switch to DECIMAL by any keyboard press except Enter.\n"
			<< "Press Enter to end the calculation.\n"
			<< "-----------------------------------------------------------------\n" << std::endl;
		for (unsigned i = 1; i < m; i++)
		{
			std::cout << "x_" << i << " = " << decimal_to_fraction(det_is(D[i]) / D0) << std::endl;
		}
		while (1)
		{
			if (_kbhit())
			{
				if (_getch() != '\r') // not Enter
				{
					// This is used to get the second char,
					// because some keyboard presses have two chars.
					if (_getch());
					// return to the front of the line (\r)
					// cover the initial input by pressing the keyboard
					std::cout << "\r\t\r\n-----------------------------------------------------------------\n" << std::endl;
					for (unsigned i = 1; i < m; i++)
					{
						std::cout << "x_" << i << " = " << det_is(D[i]) / D0 << std::endl;
					}
				}
				else std::cout << "\r";
				std::cout << "\n=================================================================" << std::endl;
				break;
			}
		}
	}
	else
	{
		std::cout << "\n-----------------------------------------------------------------" << std::endl;
		std::cout << "\nNo finite solution!" << std::endl;
		std::cout << "\n=================================================================" << std::endl;
	}
	std::cout << std::endl;

	cursor("show");
}
#endif // !_FORMULA_

Fraction.h

#ifndef _FRACTION_
#define _FRACTION_
#include <string>
#include <vector>

constexpr double epsilon = 1E-10;

std::string decimal_to_fraction(double n)
{
	std::string fra = "";
	std::string sgn = (n >= 0) ? "" : "-";
	n = fabs(n);
	if (n - static_cast<int>(n) < epsilon)
	{
		fra = std::to_string(static_cast<int>((sgn == "") ? n : -n));
		return fra;
	}
	else if (n - static_cast<int>(n) > 1 - epsilon)
	{
		fra = std::to_string(static_cast<int>((sgn == "") ? n + 1 : -n - 1));
		return fra;
	}
	else
	{
		std::vector<int> denominator;
		for (int i = 2; i <= 100000; i++)
			denominator.push_back(i);
		for (auto c : denominator) // every prime numbers within 1000
		{
			if (c * n - static_cast<int>(c * n) < epsilon)
			{
				fra = sgn + std::to_string(static_cast<int>(c * n)) + "/" + std::to_string(c);
				return fra;
			}
			if (c * n - static_cast<int>(c * n) > 1 - epsilon)
			{
				fra = sgn + std::to_string(static_cast<int>(c * n) + 1) + "/" + std::to_string(c);
				return fra;
			}
		}
	}
	return std::to_string((sgn == "") ? n : -n);
}

int cal_length(double n)
{
	double temp = n;
	int alr = 1;
	for (int i = 0; i != 9; i++)
	{
		if ((fabs(temp)) < 1)
		{
			alr = max(i, 1);
			break;
		}
		else temp /= 10;
	}
	for (int i = alr; i != 9; i++)
	{
		if (fabs(n - static_cast<int>(n)) < epsilon || fabs(n - static_cast<int>(n)) > 1 - epsilon)
		{
			i = (n >= 0) ? i : i + 1;
			return (i == alr) ? i : i + 1;
		}
		else n *= 10;
	}
	return (n >= 0) ? 9 : 10; // the default length
}

#endif // !_FRACTION_

Inverse.h

#ifndef _INVERSE_
#define _INVERSE_
#include "Cinvec.h"
#include "Algebraic cofactor.h"
#include "Cursor.h"
#include <iomanip>

std::deque<std::deque<double>> inverse_is(std::deque<std::deque<double>> A)
{
	std::deque<std::deque<double>> A_1 = A;
	if (A.size() == 1)
	{
		A_1[0][0] = 1 / A[0][0];
	}
	else
	{
		for (int i = 0; i != A.size(); i++)
		{
			for (int j = 0; j != A.size(); j++)
			{
				A_1[j][i] = exclude(A, i, j) / det_is(A);
			}
		}
	}
	return A_1;
}

void inverse()
{
	std::deque<std::deque<double>> A;
	std::cout << "Please input an n-order Matrix:\n" << std::endl;
	cinvec_s(A);
	cursor("hide");
	std::cout << "\n-----------------------------------------------------------------" << std::endl;
	if (fabs(det_is(A)) < epsilon)
	{
		std::cout << "\nIt is a singular matrix." << std::endl;
	}
	else
	{
		std::cout << "By default you view the result in the FRACTION form.\n"
			<< "You can switch to DECIMAL by any keyboard press except Enter.\n"
			<< "Press Enter to end the calculation.\n"
			<< "-----------------------------------------------------------------\n" << std::endl;
		std::cout << "The inversed matrix is:\n" << std::endl;
		std::deque<std::deque<double>> A_1 = inverse_is(A);
		int length = 0;
		for (int i = 0; i != A_1.size(); i++)
		{
			for (int j = 0; j != A_1.size(); j++)
			{
				length = max(length, decimal_to_fraction(A_1[i][j]).length());
			}
		}
		std::cout << "┌" << std::setw(A_1.size() * (length + 1) + 2) << "┐" << std::endl;
		for (auto c1 : A_1)
		{
			std::cout << "│";
			for (auto c2 : c1)
			{
				std::cout << std::setw(length + 1) << decimal_to_fraction(c2);
			}
			std::cout << "│" << std::endl;
		}
		std::cout << "└" << std::setw(A_1.size() * (length + 1) + 2) << "┘" << std::endl;

		while (1)
		{
			if (_kbhit())
			{
				if (_getch() != '\r') // not Enter
				{
					// This is used to get the second char,
					// because some keyboard presses have two chars.
					if (_getch());
					// return to the front of the line (\r)
					// cover the initial input by pressing the keyboard
					std::cout << "\r\t\r\n-----------------------------------------------------------------\n" << std::endl;
					length = 0;
					for (int i = 0; i != A_1.size(); i++)
					{
						for (int j = 0; j != A_1.size(); j++)
						{
							length = max(length, cal_length(A_1[i][j]));
						}
					}
					std::cout << "┌" << std::setw(A_1.size() * (length + 1) + 2) << "┐" << std::endl;
					for (auto c1 : A_1)
					{
						std::cout << "│";
						for (auto c2 : c1)
						{
							std::cout << std::setw(length + 1) << c2;
						}
						std::cout << "│" << std::endl;
					}
					std::cout << "└" << std::setw(A_1.size() * (length + 1) + 2) << "┘" << std::endl;
				}
				break;
			}
		}
	}
	std::cout << "\n=================================================================\n" << std::endl;
}
#endif // ! _INVERSE_

Multiply.h

#ifndef _MULTIPLY_
#define _MULTIPLY_
#include "Cinvec.h"
#include "Fraction.h"
#include <iomanip>

void multiply()
{
	unsigned m = 0, s = 0, t = 0, n = 0;
	std::vector<std::vector<double>> A, B, C; //A[m][s], B[t][n], C[m][n]

	int index = 0;
	std::string str;
	std::vector<double> row1;
	std::cout << "Please input Matrix A, input 'end' after finishing inputting.\n" << std::endl;
	do
	{
		row1 = cinvec_d(str, index);
		s = (row1.size() > s) ? row1.size() : s;
		if (!row1.empty())A.push_back(row1);
		row1.clear();
	} while (index == 0);
	m = A.size();

	index = 0;
	std::cout << "\n-----------------------------------------------------------------\n" << std::endl;
	std::cout << "Please input Matrix B, input 'end' after finishing inputting.\n" << std::endl;
	std::vector<double> row2;
	do
	{
		row2 = cinvec_d(str, index);
		n = (row2.size() > n) ? row2.size() : n;
		if (!row2.empty()) B.push_back(row2);
		row2.clear();
	} while (index == 0);
	t = B.size();

	// define C
	for (int i3 = 0; i3 != m; i3++)
	{
		std::vector<double> dvec;
		for (int j3 = 0; j3 != n; j3++)
			dvec.push_back(0);
		C.push_back(dvec);
	}

	// calculate

	int length = 0;
	if (s == t)
	{
		for (int i3 = 0; i3 != m; i3++)
		{
			for (int j3 = 0; j3 != n; j3++)
			{
				for (int k = 0; k != s; k++)
				{
					if (C.size() == m && C[i3].size() == n)
					{
						C[i3][j3] += A[i3][k] * B[k][j3];
						length = max(length, cal_length(C[i3][j3]));
					}
					else
					{
						std::cout << "\nError!" << std::endl;
						std::cout << "\n=================================================================\n" << std::endl;
						return;
					}
				}
			}
		}
		std::cout << "\n-----------------------------------------------------------------\n" << std::endl;
		std::cout << "Matrix A * B =\n" << std::endl;
		std::cout << "┌" << std::setw(m * (length + 1) + 2) << "┐" << std::endl;
		for (auto c1 : C)
		{
			std::cout << "│";
			for (auto c2 : c1)
			{
				std::cout << std::setw(length + 1) << c2;
			}
			std::cout << "│" << std::endl;
		}
		std::cout << "└" << std::setw(m * (length + 1) + 2) << "┘" << std::endl;
	}
	else
	{
		std::cout << "\n-----------------------------------------------------------------\n" << std::endl;
		std::cout << "\nError!" << std::endl;
	}
	std::cout << "\n=================================================================\n" << std::endl;
}
#endif // !_MULTIPLY_

Transpose.h

#ifndef _TRANSPOSE_
#define _TRANSPOSE_
#include "Cinvec.h"
#include "Fraction.h"
#include <iomanip>

void transpose()
{
	int m = 0, s = 0;
	std::deque<std::deque<double>> to_T; // to_T[m][s]
	std::cout << "Please input a Matrix, input 'end' after finishing inputting.\n" << std::endl;

	int index = 0;
	std::string str;
	std::deque<double> row1;
	do
	{
		row1 = cindeq_d(str, index);
		s = (row1.size() > s) ? row1.size() : s;
		if (!row1.empty())to_T.push_back(row1);
		row1.clear();
	} while (index == 0);
	m = to_T.size();

	int length = 0;
	std::vector<std::vector<double>> opt;
	for (int j = 0; j != s; j++)
	{
		std::vector<double> temp;
		for (int i = 0; i != m; i++)
		{
			if (to_T[i].size() != s || to_T.size() != m)
			{
				std::cout << "\n-----------------------------------------------------------------\n" << std::endl;
				std::cerr << "Illeagal input!" << std::endl;
				std::cout << "\n=================================================================\n" << std::endl;
				return;
			}
			else
			{
				temp.push_back(to_T[i][j]);
				length = max(length, cal_length(to_T[i][j]));
			}
		}
		opt.push_back(temp);
	}
	std::cout << "\n-----------------------------------------------------------------\n" << std::endl;
	std::cout << "The transposed matrix is:" << std::endl;
	std::cout << "┌" << std::setw(m * (length + 1) + 2) << "┐" << std::endl;
	for (auto c1 : opt)
	{
		std::cout << "│";
		for (auto c2 : c1)
		{
			std::cout << std::setw(length + 1) << c2;
		}
		std::cout << "│" << std::endl;
	}
	std::cout << "└" << std::setw(m * (length + 1) + 2) << "┘" << std::endl;
	std::cout << "\n=================================================================\n" << std::endl;
}

#endif // !_TRANSPOSE_

分析


ALL RIGHTS RESERVED © 2020 Teddy van Jerry
欢迎转载,转载请注明出处。


See also

Teddy van Jerry 的导航页

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值