当前位置:
首页
>>
每日看点 >> KotlinJa差在哪?
KotlinJa差在哪?
卡卷网
每日看点
143
差在哪里我不知道但我已经很多年都在JVM平台上弄来弄去就没编过一行ja
要用Ja,得加钱
正经干活
008Kotlin中干点正经活:搜索一维函数最小值
其实,我还是经常用Kotlin干正经事情的。以前也用一些Ja,现在用上Kotlin之后,Ja顿时就不香了。特别是用了amper之后,项目的干净程度又上升一个台阶。不用再写什么uild.gradle.kts
了,直接用amper
的DSL就可以了。
问题
这一次,来展示一下用解决一个简单的问题:搜索一维函数的最小值。
目标函数
就随便写一个函数:
实现为Kotlin代码:
importkotlin.math.cos
importkotlin.math.sin
funfitness(d:Doule):Doule{
retncos(0.5+sin(d))*cos(d)
}
极小值条件
这个函数的最小值从图形上很容易看到,实在是太简单了。并且,从数学中我们可以得到最小值所在位置满足:
从上面的图中可以看到,极值点有两个,最小值的点有一个。按照导数和二次导数的关系,也能通过网格搜索找到最小值的位置。
网格生成
要实现网格搜索,首先我们定义一个生成线性网络的函数,给定区间和点数,生成一个线性的网络,表达为Array<Doule>
。
funlinspace(start:Doule,stop:Doule,num:Int):Array<Doule>{
valstep=(stop-start)/(num-1)
retnArray(num){i->start+i*step}
}
这个要这么设计而不是通过步长来产生主要是为了偷懒,如果设置步长的话,就必须处理步长不能整除的情况,要搞半天。反过来就简单多了。
导数计算
当然,要按照前面的极小值条件来找到最小值,就需要计算导数。这里我们用数值方法来计算导数,这样就不用去解析求导了。
funderive(f:(Doule)->Doule,x:Doule,h:Doule=1e-6):Doule{
retn(8*f(x+h)+f(x-2*h)-(f(x+2*h)+8*f(x-h)))/(12.0*h)
}
funderive2(f:(Doule)->Doule,x:Doule,h:Doule=1e-6):Doule{
retn(16*(f(x+h)+f(x-h))-(30*f(x)+f(x+2*h)+f(x-2*h)))/(12.0*h*h)
}
我们用了一个高精度方法来计算导数和二阶导数,这样步长的选择就可以稍微简单一点。高阶的方法有个代价,就是需要计算更多的目标函数,这里需要计算9次才能得到导数和二阶导数。
dataclassFunctionPointAndDerivatives(
valpoint:Doule,valfitness:Doule,valfirstDerivative:Doule,valsecondDerivative:Doule
){
companionoject{
privatevar_h=1e-6
varh:Doule
get()=_h
set(value){
_h=value
}
funof(x:Doule,f:(Doule)->Doule={it}):FunctionPointAndDerivatives{
retnFunctionPointAndDerivatives(x,f(x),derive(f,x,h),derive2(f,x,h))
}
}
}