一、直接上代码!
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
class LinearRegression
{
private:
int k;
double* data_a;
double* data_b;
double x_average;
bool x_average_mark;
double y_average;
bool y_average_mark;
double xy_average;
bool xy_average_mark;
double xx_average;
bool xx_average_mark;
double yy_average;
bool yy_average_mark;
double a;
bool a_mark;
double b;
bool b_mark;
double r;
bool r_mark;
double u_a;
bool u_a_mark;
double u_b;
bool u_b_mark;
double u_c;
bool u_c_mark;
double u_d;
bool u_d_mark;
void cal_x_average();
void cal_y_average();
void cal_xy_average();
void cal_xx_average();
void cal_yy_average();
void pri_cal_u_a();
void pri_cal_u_b();
void pri_cal_u_c();
void pri_cal_u_d();
public:
LinearRegression(int p_k);
~LinearRegression();
bool accuire_data(std::string& file_name);
void reverse_data(std::string choice="a");
double cal_a();
double cal_b();
double cal_r();
double cal_u_a();
double cal_u_b();
double cal_u_c();
double cal_u_d();
};
int main(int argc,char** argv)
{
//本程序有两个参数,第一个参数为k,第二个参数为数据文件(txt格式)
if (argc!=3)
return 1;
std::string length_string=(std::string)argv[1];
std::string name_string=(std::string)argv[2];
//创建一个自定义的LinearRegression类的对象实例example
LinearRegression example(std::stoi(length_string));
//获取数据,调用accuire_data方法
example.accuire_data(name_string);
//将因变量组的所有元素取倒数
//这个函数用于自变量或因变量组的所有元素取倒数
//参数为"a",则对自变量组取倒数;参数为"b",则对因变量组取倒数。
//如果不需要取倒数,直接注释这一行即可。
//example.reverse_data("b");
//调用cal_a方法计算a
std::cout<<"a:"<<example.cal_a()<<std::endl;
//调用cal_b方法计算b
std::cout<<"b:"<<example.cal_b()<<std::endl;
//调用cal_r方法计算r
std::cout<<"r:"<<example.cal_r()<<std::endl;
//调用cal_u_a方法计算a的A类不确定度
std::cout<<"u_a(a):"<<example.cal_u_a()<<std::endl;
//调用cal_u_b方法计算b的A类不确定度
std::cout<<"u_a(b):"<<example.cal_u_b()<<std::endl;
//调用cal_u_c方法计算a的B类不确定度
std::cout<<"u_b(a):"<<example.cal_u_c()<<std::endl;
//调用cal_u_d方法计算b的B类不确定度
std::cout<<"u_b(b):"<<example.cal_u_d()<<std::endl;
//以上7个方法均可以单独使用。
//我已经把可能存在的问题解决了!
}
LinearRegression::LinearRegression(int p_k)
{
k=p_k;
data_a=new double [k];
data_b=new double [k];
x_average_mark=false;
y_average_mark=false;
xy_average_mark=false;
xx_average_mark=false;
yy_average_mark=false;
a_mark=false;
b_mark=false;
r_mark=false;
u_a_mark=false;
u_b_mark=false;
u_c_mark=false;
u_d_mark=false;
}
LinearRegression::~LinearRegression()
{
delete [] data_a;
delete [] data_b;
}
bool LinearRegression::accuire_data(std::string& file_name)
{
using namespace std;
ifstream file(file_name);
string double_string;
char ch;
int j;
if (file.is_open())
{
for (int i=0;i<k;i++)
{
j=0;
double_string="";
while(1)
{
ch=file.get();
if (ch>='0'&&ch<='9'||ch=='.')
double_string[j++]=ch;
else
break;
}
data_a[i]=std::stod(double_string);
}
for (int i=0;i<k;i++)
{
j=0;
double_string="";
while(1)
{
ch=file.get();
if (ch>='0'&&ch<='9'||ch=='.')
double_string[j++]=ch;
else
break;
}
data_b[i]=std::stod(double_string);
}
return true;
}
else
{
return false;
}
}
void LinearRegression::reverse_data(std::string choice)
{
if (choice=="a")
for (int i=0;i<k;i++)
data_a[i]=1/data_a[i];
else if (choice=="b")
for (int i=0;i<k;i++)
data_b[i]=1/data_b[i];
}
void LinearRegression::cal_x_average()
{
if (x_average_mark==false)
{
double sum=0;
for (int i=0;i<k;i++)
sum+=data_a[i];
x_average=sum/k;
x_average_mark=true;
}
}
void LinearRegression::cal_y_average()
{
if (y_average_mark==false)
{
double sum=0;
for (int i=0;i<k;i++)
sum+=data_b[i];
y_average=sum/k;
y_average_mark=true;
}
}
void LinearRegression::cal_xy_average()
{
if (xy_average_mark==false)
{
double sum=0;
for (int i=0;i<k;i++)
sum+=data_a[i]*data_b[i];
xy_average=sum/k;
xy_average_mark=true;
}
}
void LinearRegression::cal_xx_average()
{
if (xx_average_mark==false)
{
double sum=0;
for (int i=0;i<k;i++)
sum+=data_a[i]*data_a[i];
xx_average=sum/k;
xx_average_mark=true;
}
}
void LinearRegression::cal_yy_average()
{
if (yy_average_mark==false)
{
double sum=0;
for (int i=0;i<k;i++)
sum+=data_b[i]*data_b[i];
yy_average=sum/k;
yy_average_mark=true;
}
}
double LinearRegression::cal_a()
{
if (a_mark==false)
{
this->cal_y_average();
this->cal_x_average();
this->cal_b();
a=y_average-b*x_average;
a_mark=true;
}
return a;
}
double LinearRegression::cal_b()
{
if (b_mark==false)
{
this->cal_x_average();
this->cal_y_average();
this->cal_xy_average();
this->cal_xx_average();
b=(x_average*y_average-xy_average)/(x_average*x_average-xx_average);
b_mark=true;
}
return b;
}
double LinearRegression::cal_r()
{
if (r_mark==false)
{
this->cal_x_average();
this->cal_y_average();
this->cal_xy_average();
this->cal_xx_average();
this->cal_yy_average();
r=(xy_average-x_average*y_average)/sqrt((xx_average-x_average*x_average)*(yy_average-y_average*y_average));
r_mark=true;
}
return r;
}
void LinearRegression::pri_cal_u_b()
{
if (u_b_mark==false)
{
u_b=b*sqrt((1/(r*r)-1)/(k-2));
u_b_mark=true;
}
}
void LinearRegression::pri_cal_u_a()
{
this->pri_cal_u_b();
if (u_a_mark==false)
{
u_a=sqrt(xx_average)*u_b;
u_a_mark=true;
}
}
void LinearRegression::pri_cal_u_c()
{
this->pri_cal_u_d();
if (u_c_mark==false)
{
u_c=sqrt(xx_average)*u_d;
u_c_mark=true;
}
}
void LinearRegression::pri_cal_u_d()
{
if (u_d_mark==false)
{
double u_b_y;
std::cout<<"Please input the type B evaluation of uncertainty of dependent variable --- y:"<<std::endl;
std::cout<<"(Attention! Do not forget the confidence coefficient)"<<std::endl;
std::cin>>u_b_y;
u_d=u_b_y*sqrt(1/(k*(xx_average-x_average*x_average)));
u_d_mark=true;
}
}
double LinearRegression::cal_u_a()
{
this->pri_cal_u_a();
return u_a;
}
double LinearRegression::cal_u_b()
{
this->pri_cal_u_b();
return u_b;
}
double LinearRegression::cal_u_c()
{
this->pri_cal_u_c();
return u_c;
}
double LinearRegression::cal_u_d()
{
this->pri_cal_u_d();
return u_d;
}
二、使用注意事项
1、基本使用方法
复制上面这个代码段到新的cpp文件后编译。
2、C++11标准
由于调用了string库中的std::stod()函数,所以需要以C++11标准对此cpp文件进行编译。
具体方法可以参考:
DEV c++中添加c++11编译环境_devcpp支持c11_中国“名猿”的博客-CSDN博客
3、数据文件
该程序运行依赖数据文件(txt格式), 把数据文件和cpp原文件放在一个文件夹里!
并且,数据文件需要按如下方式处理:
假设数据量为k,则需要输入2k组double型数据。数据与数据之间用任意单个空格符/换行符分割!
4、运行参数
本程序有两个参数,第一个参数为k,第二个参数为数据文件(txt格式)。运行参数可以如下输入:
5 test.txt
其中前者为数据量,后者为数据文件名称。
具体如何添加运行参数,可以参考下面这一篇文章:
关于devc++中程序运行参数的输入问题_如何用dev运行命令行参数_yupl的博客-CSDN博客
又或者,你可以直接用控制台!
5、类方法
一共包含了9个公有类方法。其中第一个方法必须是accuire_data,用于获取数据;第二个方法可以选择按照自身需求对数据取倒数(也可以不执行!看你的需要!)
其他7个方法可以按照任意顺序调用。
三、写在后面
所有的函数和变量都被封装在了LinearRegression类中。欢迎各位大神继承这个类编写更多功能,也欢迎直接大刀阔斧地改写这个类!