这篇文章是我分享PPT内容的总结,主要讲述如何使用逼近算法解决工作中的一些棘手问题,通过解决具体场景的问题进行分析。
前序:算法是什么
算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。简单而言算法就是解决问题的步骤,其特征:
1,有穷性(Finiteness):算法的有穷性是指算法必须能在执行有限个步骤之后终止;
2,确切性(Definiteness):算法的每一步骤必须有确切的定义;
3,输入项(Input):一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件;
4,输出项(Output):一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;
5,可行性(Effectiveness):算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步,即每个计算步都可以在有限时间内完成(也称之为有效性)。
程序=数据+逻辑(算法),任何简单或者复杂的算法都可以由顺序结构、选择结构和循环结构这三种基本结构组合而成。所以这三种结构被称为程序设计的三种基本结构,也是程序化程序设计必须采用的结构。
在编写PPT的时候,我曾想如何能够生动形象的讲明白讲清楚一件事?思来量去,觉的按照一条线来比较清晰。于是用了我处理的思路流程,也是这篇文章的各个大纲:遇到问题——》分析问题——》解决问题——》思考问题——》延伸问题——》升华问题。好,下边具体讲讲各个阶段的思考。
一,业务场景是什么?
这里以金融P2P为背景:
定期理财常见业务类型:到期一次性还本付息、按月等额本息、按月等额本金,其中各类的计算公司方法如下:
1,到期一次性还本付息:
2.1,按月等额本息总金额计算:
2.2,按月等额本息每期还款本金计算:
3.1,按月等额本金计算:
定期业务中的各种计算方法,都是按照本金,计算了用于一段固定时间的利息,如果想要转化计算出用户每天得到的利息呢?
一方案是利用单利计算方法,简单将用户这段时间应得的利息除于时间段的天数,得到每天的利息。这种方案是用户体验度特别差,而且不够合理,因为每天增加利息一样,今天应得的利息,不是按照昨天的本息和计算,而是按照最初的本金计算,不合理。
二方案是利用复利计算(日、月、年复利)方法,这种方案是用户今天应得利息,是按照昨天的本息和进行计算,用户的日利息是每天不断增加的,合理。
好,场景就是利用方案二,根基定期业务的本息值,来计算出用户的日利息(类似活期的计算方式),而计算用户日利息就需要计算准确的日复利利率。
二,业务实现难点?
如何将定期计算方式和活期计算方式进行等价(定期≈活期)
推导最复杂的对按月等额本息转化活期求日复利利率的公司,根据经典的PMT公式进行推导得:
还款额/(1+x)^n1+还款额/(1+x)^n2+还款额/(1+x)^n3+……=本金(x为日利率,n表示每期还款日距起息日的天数)
难点就是如何进行公式求解,求出x日利率。
三,实现方案有哪些?
1,对公式进行推导、反解出x日复利利率=某个公式(因为涉及到分母的不同次幂,所以很难,或者没有,大家可以尝试尝试);
2,EXCEL单变量求解(工具、理论),求出来(EXCEL功能还是非常强大的),对每月天数进行四舍五入,进行配置(有误差、可实现);
3,逼近法:根据起息日和还款额计算出日复利利率,通过探测的方法,试出来,利用计算机善于做有规则、重复的功能,通过X的不断试值,来达到一个我们满意的结果(例如误差在百万分之一、千万分之一、亿分之一……)(性能控制:需要考虑这个算法对时间复杂度和空间复杂度测试评估);
探索的过程:1,首先直接去解前边的方程(通过各种数学方法,百度也好,问别人也好,自己探索也好);2,转变思路,为了实现业务,善假于物也;3,为了追求完美,找到逼近算法;
好,下来我们来看看逼近算法,逼近算法,顾名思义就是通过尝试不断靠近正确答案的一种算法。在数学中,数值逼近是研究函数的离散逼近,用适合于计算机上的计算的简单函数(如多项式,连分式等)逼近复杂函数。主要包括插值法、最佳一致逼近、最佳平方逼近与最小二乘逼近。其中的难点就是初始值的设置、步长的设置,逼近的策略(设置到逼近的次数,这个必须在可控制之内,在计算机性能之内),误差的数量级控制等。
好,下边看最简单的两种逼近,大家看下那个更好一些:
/**
* 逼近法求日利率
*
* @param info PMT公司计算的还款计划,
* @param contractAmount 起息金额
* @return
*/
public static double getExpectDateRate(HashMap info[], double contractAmount) {
double step = 0.00000001d;
double der = 1.000028d;
double n, repay;
int interval_value_date;
do {
der = new BigDecimal(step + der).setScale(8, BigDecimal.ROUND_HALF_UP).doubleValue();
n = repay = 0.0;
interval_value_date = 0;
for (int i = 0; i < info.length; i++) {
repay = (Double) (info[i].get("repay"));
interval_value_date = (Integer) (info[i].get("interval_value_date"));
n += repay / Math.pow(der, interval_value_date);
}
} while (n > contractAmount);
return new BigDecimal(der).setScale(8, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 等额本息逆推实际利率法
*
* @param Principal 本金
* @param MonthlyPayments 月还款额
* @param Period 期数
* @param Iterations 运算次数
* @param Digit 保留位数
* @return 利率
* @author ljh
*/
public static Double getYearRate(Double Principal, Double MonthlyPayments, int Period, int Iterations, int Digit) {
double rate = 1, x, jd = 0.1, side = 0.1, i = 1;
do {
x = Principal / MonthlyPayments - (Math.pow(1 + rate, Period) - 1) / (Math.pow(rate + 1, Period) * rate);
if (x * side > 0) {
side = -side;
jd *= 10;
}
rate += side / jd;
} while (i++ < Iterations && Math.abs(x) >= 1 / Math.pow(10, Digit));
if (i > Iterations) {
return Double.NaN;
}
return rate;
}
四,思考总结:
1,为什么简单的重复计算却解决了我们的难题?
2,需要考虑什么:时间复杂度、空间复杂度
3,这种算法模型的使用场景?
五,其它方面的运用?
这里简单说下最近比较火的AI。神经网络有input数据入口,Hidden算法结构,output输出结果,通过反向传播训练算法结构的参数,然后利用正向传播进行预测等。其中得到最优算法结构的参数很多算法都是通过大数据量、高重复计算,不断慢慢逼近得到的。只不过在AI的运用更加复杂而已。
六,思考升华更大的为什么?
1,问题——》目标的道路?
2,解决问题的道路都是想通的?
3,解决问题都是都非常简单?
4,解决问题都是非常难?
好,后边几个方面其实比较发散,由于是PPT的总结,这里大家仁者见仁智者见智,没有什么谁更对,只要思考这些问题,或者更多的问题就OK。