简介
这是一个用 Visual C++做的关于线性代数(尤其是与矩阵相关的计算)的小软件。
应用程序(exe)下载
链接:https://download.csdn.net/download/weixin_50012998/13115991
程序
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.0)\nTeddy van Jerry\n==============================\n" << endl;
MessageBox(NULL, L"This is TVJ Matrix Laboratory (v 1.0)\nDesigned by Teddy van Jerry\n2020.11\n\nPlease make sure that your input is legal!",
L"Information", MB_ICONINFORMATION);
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;
}
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;
}
#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 program.\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
{
// 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>(n));
return fra;
}
else if (n - static_cast<int>(n) > 1 - epsilon)
{
fra = std::to_string(static_cast<int>(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(n);
}
int cal_length(double n)
{
double temp = n;
int alr = 1;
for (int i = 0; i != 8; i++)
{
if ((fabs(temp)) < 1)
{
alr = max(i, 1);
break;
}
else temp /= 10;
}
for (int i = alr; i != 8; i++)
{
if (fabs(n - static_cast<int>(n)) < epsilon || fabs(n - static_cast<int>(n)) > 1 - epsilon)
return (i == alr) ? i : i + 1;
else n *= 10;
}
return 8; // the default length
}
#endif // !_FRACTION_
Inverse.h
#ifndef _INVERSE_
#define _INVERSE_
#include "Cinvec.h"
void inverse()
{
std::cout << "This will be released in later versions" << std::endl;
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 =" << 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 << "\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_
输出示例
已发现的bug
- 求解线性方程组若找不到分数解程序会爆掉。
- 当其中有的找不到分数解输出时会漏掉负号。
- 解方程整数时输出也会漏负号。
- 矩阵乘法在输入错误输出 Error! 时少了分割线。
- 判断输出长度时忘记考虑负号的长度。
- 使用完解方程功能输出小数解后程序会结束。
分析
-
另见我的博客 【笔记】 在 Visual C++ 中设置 exe 文件的图标。
-
另见我的博客 【笔记】 在 Visual C++ 中设置 MessageBox。
-
另见我的博客 【笔记】 在 Visual C++ 中设置网页链接。
-
(最近有些忙,以后继续写)
ALL RIGHTS RESERVED © 2020 Teddy van Jerry
欢迎转载,转载请注明出处。