我正在写一些代码作为非线性回归工具的一部分,我试图找出一种方法来返回给定函数的第n个偏导数,快速。函数(以及部分的分析表示)在运行时是已知的,可以对它们进行硬编码。这里是我到目前为止(工作):优化反复称为数学函数
let getPartials (paramVect: array<float>) idx =
let a = paramVect.[0]
let b = paramVect.[1]
let c = paramVect.[2]
match idx with
| 1 -> (fun x -> (1.0+b+c*x)**(-1.0/b)) // df(x)/da
| 2 -> (fun x -> ((a*(1.0+c*b*x)**(-(b+1.0)/b))*((b*c*x+1.0)*Math.Log(b*c*x+1.0)-b*c*x))/(b*b)) // df(x)/db
| 3 -> (fun x -> -a*x*(b*c*x+1.0)**(-(b+1.0)/b)) // df/dc
| _ -> (fun x -> 0.0) //everything else is zero
我用这是先建立一个部分功能与参数向量所以,我尽量减少需要在传递次数的方式然后我重复地调用(getPartials(i)x_val)来构造一个jacobian。这个函数在程序的生命周期中被调用了很多次。
但是,我认为它可以得到改善,我得到了非常可以接受的性能。分析表明,对第二功能计算(长计算)的评估是一个cpu排放 - 可以优化吗?我不确定,如果匿名函数创建一个性能问题,为可读,因为它是...
我全新到F#编程,所以请让你发现任何egregarious问题,我知道,无论是风格/形式或表演!
谢谢
更新:落实JohnPalmer和重构建议修改完成后,不用返回其接受x值作为参数的匿名功能,而不是做整个计算就地而言,我看到的速度大约提高了300%。能够返回部分功能更方便,但不值得花费。
let getPartials (paramVect: array<float>) idx x =
let a = paramVect.[0]
let b = paramVect.[1]
let cbx = paramVect.[1] * paramVect.[2] * x
match idx with
| 1 -> (1.0+cbx)**(-1.0/b) // df(x)/da
| 2 -> ((a*(1.0+cbx)**(-(b+1.0)/b))*((cbx+1.0)*Math.Log(cbx+1.0)-cbx))/(b**2.0) // df(x)/db
| 3 -> -a*x*(cbx+1.0)**(-(b+1.0)/b) // df/dc
| _ -> 0.0 //everything else is zero
有,你可以转换为常数,这可能有助于一些公共子 - 例如'b * c * x'。如果您知道某些参数总是大或小,则可能会以牺牲准确性为代价简化某些表达式。另外,如果你可以接受精确度惩罚,float32比float更快。 – 2014-09-29 22:09:39
@JohnPalmer我确定我读过float32通常比float更慢的原因,因为计算实际上是在FPU中以相同的精度完成的,但对于float32,在截断值时有更多的舍入操作。 – phoog 2014-09-29 22:27:59
Profiler实际上是否表示速度增加是由于乘法的数量减少?检查你的GC统计数据 - 这使我更有可能获得改进的性能。 – phoog 2014-09-29 22:49:59