软件技术中心的例会终于也轮到我了,为了给小伙伴们讲一点干货,于是开始了为期一周的学习,从百度知乎博客到请教学长(JY大佬)甚至查阅相关书籍资料,终于有所收获,并对其产生了浓厚兴趣,希望以后能够在这方面有更大的进步。
#include<bits/stdc++.h>
using namespace std;
double cx[1000000],cy[1000000],cz[1000000]; //存储测试数据的数组
int main(){
int sum;
double a1,b1,c1,vol,max;
printf("请输入生成数据的数量:");
cin>>sum;
printf("请输入数据上限:");
cin>>max;
printf("\n请输入计算公式的两个系数和一个常数\n\n");
printf("a=");
cin>>a1;
printf("\nb=");
cin>>b1;
printf("\nc=");
cin>>c1;
printf("\n\n请输入生成数据的误差百分比:");
cin>>vol;
srand(time(NULL));
for(int k=0;k<sum;k++){
cx[k]=(double)rand()/RAND_MAX*max;
cy[k]=(double)rand()/RAND_MAX*max;
cz[k]=(a1*cx[k]+b1*cy[k]+c1)*((((double)rand()/RAND_MAX*2-1)*vol)+1);
}
FILE *fp1;
fp1=fopen("xunlian.txt","w");
for(int k=0;k<sum;k++)
fprintf(fp1,"%lf %lf %lf ",cx[k],cy[k],cz[k]);
fclose(fp1);
cout<<"成功!";
}
#include<bits/stdc++.h>
using namespace std;
//一些全局变量
double xx=0,yy=0,zz=0; //平均数
int i;
int num; //数据数
double a,b,c; //系数
double x[1000000],y[1000000],z[1000000]; //两个自变量和一个因变量(z)
//读取数据的函数
void duqu(){
printf("请输入要从“xunlian.txt”中获得的训练数据组数:");
scanf("%d",&num);
FILE *fp; //打开文档
fp=fopen("xunlian.txt","r");
for(i=0;i<num;i++){
fscanf(fp,"%lf",&x[i]);
fscanf(fp,"%lf",&y[i]);
fscanf(fp,"%lf",&z[i]);
}
fclose(fp); //关闭文档
}
//求平均数的函数
void jun(){
for(i=0;i<num;i++){
xx+=x[i];
yy+=y[i];
zz+=z[i];
}
xx/=num;
yy/=num;
zz/=num;
}
//对积的求和函数
double two(double *q,double *qq){
double qa=0;
for(i=0;i<num;i++) qa+=q[i]*qq[i];
return qa;
}
//最小二乘法求方程系数的函数(核心)
void xishu(){
b=(two(x,z)*two(y,y)-two(y,z)*two(x,y))/(two(x,x)*two(y,y)-two(x,y)*two(x,y));
c=(two(y,z)*two(x,x)-two(x,z)*two(x,y))/(two(x,x)*two(y,y)-two(x,y)*two(x,y));
a=zz-b*xx-c*yy;
}
//开始计算
void jisuan(){
printf("\n系数分别为:\n\n%.16lf\n\n%.16lf\n\n",c,b);
printf("%.16f\n\n请输入测试数据:",a);
double ans,x1,y1;
scanf("%lf %lf",&x1,&y1);
ans=c*x1+b*y1+a;
printf("\n答案近似为:%.16lf\n\n",ans);
}
int main(){
for(;;){
duqu(); //读取数据
jun(); //求平均数
xishu(); //求系数
jisuan(); //开始计算
}
}
#include<bits/stdc++.h>
using namespace std;
//一些全局变量
int i;
int num; //数据数
double a,b,c,c11; //系数
double x[10000],y[10000],z[10000]; //两个自变量和一个因变量(z)
//读取数据的函数
void duqu(){
printf("请输入要从“xunlian.txt”中获得的训练数据组数:");
scanf("%d",&num);
FILE *fp; //打开文档
fp=fopen("xunlian.txt","r");
for(i=0;i<num;i++){
fscanf(fp,"%lf",&x[i]);
fscanf(fp,"%lf",&y[i]);
fscanf(fp,"%lf",&z[i]);
}
fclose(fp); //关闭文档
}
//不断优化的方法求方程系数的函数(核心)
void xishu(){
srand(time(NULL));
double wu,ans,nn=0;
for(i=0;i<num;i++)
wu=wu+z[i]*z[i];
cout<<"初始误差:"<<wu<<endl;
int m;
for(;;){
m=0;
a=a+0.01;
ans=0;
for(i=0;i<num;i++)
ans=ans+(z[i]-a*x[i]-b*y[i]-c)*(z[i]-a*x[i]-b*y[i]-c);
if(ans>=wu) { a=a-0.01;m++;}
else wu=ans;
printf("%lf\n",wu);
a=a-0.01;
ans=0;
for(i=0;i<num;i++)
ans=ans+(z[i]-a*x[i]-b*y[i]-c)*(z[i]-a*x[i]-b*y[i]-c);
if(ans>=wu) { a=a+0.01;m++;}
else wu=ans;
printf("%lf\n",wu);
b=b+0.01;
ans=0;
for(i=0;i<num;i++)
ans=ans+(z[i]-a*x[i]-b*y[i]-c)*(z[i]-a*x[i]-b*y[i]-c);
if(ans>=wu) { b=b-0.01;m++;}
else wu=ans;
printf("%lf\n",wu);
b=b-0.01;
ans=0;
for(i=0;i<num;i++)
ans=ans+(z[i]-a*x[i]-b*y[i]-c)*(z[i]-a*x[i]-b*y[i]-c);
if(ans>=wu) { b=b+0.01;m++;}
else wu=ans;
printf("%lf\n",wu);
c=c+0.01;
ans=0;
for(i=0;i<num;i++)
ans=ans+(z[i]-a*x[i]-b*y[i]-c)*(z[i]-a*x[i]-b*y[i]-c);
if(ans>=wu) { c=c-0.01;m++;}
else { wu=ans;c11=c;}
printf("%lf\n",wu);
c=c-0.01;
ans=0;
for(i=0;i<num;i++)
ans=ans+(z[i]-a*x[i]-b*y[i]-c)*(z[i]-a*x[i]-b*y[i]-c);
if(ans>=wu) { c=c+0.01;m++;}
else { wu=ans;c11=c;}
printf("%lf\n",wu);
if(m==6) break;
}
}
//开始计算
void jisuan(){
printf("\n系数分别为:\n\n%.16lf\n\n%.16lf\n\n",a,b);
printf("%.16f\n\n请输入测试数据:",c11);
double ans,x1,y1;
scanf("%lf %lf",&x1,&y1);
ans=a*x1+b*y1+c11;
printf("\n答案近似为:%.16lf\n\n",ans);
}
int main(){
for(;;){
duqu(); //读取数据
xishu(); //优化系数
jisuan(); //开始计算
}
}
/*
_ooOoo_
o8888888o
88" . "88
(| -_- |)
O\ = /O
____/`---'\____
.' \\| |// `.
/ \\||| : |||// \
/ _||||| -:- |||||- \
| | \\\ - /// | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . __
."" '< `.___\_<|>_/___.' >'"".
| | : ` - `.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
======`-.____`-.___\_____/___.-`____.-'======
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG
*/
#include<bits/stdc++.h>
using namespace std;
//一些全局变量
int i;
int num; //数据数
double a,b,a1,b1; //系数
double x[10000],y[10000],z[10000]; //两个自变量和一个因变量(z)
//读取数据的函数
void duqu(){
printf("请输入要从“xunlian.txt”中获得的训练数据组数:");
scanf("%d",&num);
FILE *fp; //打开文档
fp=fopen("xunlian.txt","r");
for(i=0;i<num;i++){
fscanf(fp,"%lf",&x[i]);
fscanf(fp,"%lf",&y[i]);
fscanf(fp,"%lf",&z[i]);
}
fclose(fp); //关闭文档
}
//不断优化的方法求方程系数的函数(核心)
void xishu(){
double wu,ans,wu0;
for(i=0;i<num;i++)
wu=wu+z[i]*z[i];
wu0=wu;
cout<<"初始误差:"<<wu<<endl;
for(a=0;a<5;a=a+0.001){
for(b=0;b<5;b=b+0.001){
ans=0;
for(i=0;i<num;i++)
ans=ans+(z[i]-a*x[i]-b*y[i])*(z[i]-a*x[i]-b*y[i]);
if(ans<wu){
wu=ans;
a1=a;
b1=b;
printf("%.3lf %.3lf\n",a,b);
}
}
}
}
//开始计算
void jisuan(){
printf("\n系数分别为:\n\n%.3lf\n\n%.3lf\n\n",a1,b1);
printf("请输入测试数据:");
double ans,x1,y1;
scanf("%lf %lf",&x1,&y1);
ans=a1*x1+b1*y1;
printf("\n答案近似为:%.16lf\n\n",ans);
}
int main(){
for(;;){
duqu(); //读取数据
xishu(); //优化系数
jisuan(); //开始计算
}
}
/*
_ooOoo_
o8888888o
88" . "88
(| -_- |)
O\ = /O
____/`---'\____
.' \\| |// `.
/ \\||| : |||// \
/ _||||| -:- |||||- \
| | \\\ - /// | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . __
."" '< `.___\_<|>_/___.' >'"".
| | : ` - `.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
======`-.____`-.___\_____/___.-`____.-'======
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG
*/
// 梯度下降算法求一元凸函数的最优解(极值点)
// 梯度下降算法 X(n+1) = X(n) - ηf'(X)
// 设一元凸函数 y = ax^2 + bx + c (a > 0)
// 1.构造一元凸函数
float a = 1; // a > 0
float b = 2;
float c = 3;
// 2.设置下降起点和下降率(学习率)
float Xn1, Xn0; // X(n+1) 和 X(n)
Xn0 = 10; // 下降起点
// 下降率yita,该值越小,下降越慢(训练过程越慢),结果越准确,该值越大,下降越快(训练过程越快),结果越不准确,
// 当值超过一定的值时,结果无法收敛,将发散。
float yita = 0.001;
float det = 0.001; // 用于利用极限求导数
float thresh = 0.000001; // 判断收敛的阈值
int times = 0; // 迭代次数
// 3.开始梯度迭代
while (1)
{
// 极限法求导数(不使用解析解,因为大部分情况下无法直接求得解析解)
// f(x+det) - f(x)
// lim = -----------------------
//(det->0) det
//
float Xgap = Xn0 + det;
float Fdiv = (((a * Xgap * Xgap) + (b * Xgap) + c) - ((a * Xn0 * Xn0) + (b * Xn0) + c)) / det; // 在Xn0处的导数
Xn1 = Xn0 - yita * Fdiv;
times++;
// 如果梯度下降趋于稳定(下降幅度基本不变),就认为下降已经收敛,找到最优解。
if (fabs(Xn1 - Xn0) < thresh){
cout << "yita = " << yita << endl;
cout << "Best value: " << Xn1 << endl;
cout << "Iteration times: " << times << endl;
break;
}
Xn0 = Xn1;
}