我有一个相当复杂的算法执行搜索,我在某个范围内使用$search
变量[0.25到1.75]。
基于算法,当$search
正好为1时会发生“有趣”的事情,因为它会触及有时(但并非总是)最有利的变量配置。一些代码依赖于$search
正好为1来产生最有利的结果。
更具体地说,搜索范围内通常会有一些特定的值,这会产生最有利的结果,但是我的算法的布局方式,通常会跳过特定的值。这里我列出了一个例子,当那个特定的值(基于其他输入和配置)恰好恰好是1 ..
问题
从数学上讲,如果$search
是连续的而不是谨慎的话,我就不会有这个问题。我的问题是尝试使用离散数学收敛于最有利的变量配置。这里的问题是算法。需要注意的次要问题是浮点运算,但我不认为这是问题。
基本循环:
$maxPowerOut = 0 ;
for ($increment = 0; $increment <= 500; $increment ++)
{
//vars computed elsewhere, i.e:
//MIN = 0.24651533;
//STEP = 0.00196969
$search = MIN + STEP * $increment;
//compute several coefficients (returns an array)
$coeff = $this->coefficient($search);
//design is a complex library function
list($a, $b) = $this->design($coeff);
$powerOut = $a * $b;
//keep track of max power (and other params, not shown)
if ($powerOut > $maxPowerOut)
$maxPowerOut = $PowerOut;
}
//currently prints 899.993 instead of 900 as should be expected
print "Max Power is $maxPowerOut";
当然,$search
几乎不是1。它是这样的:
注意在上面的循环中如何跳过1。为了论证,让我们说最有利的位置发生在1.003000。该值(1.003000)也将被跳过。
问题
如何改进,重组,重新思考,重新组织,重写我的循环以避免此类问题?
答案 0 :(得分:1)
一个简单的改进可能是使用迭代方法:
在当前循环中,您搜索区间[0.25,1.75]中的500个值。假设您可以通过这种方式将最佳范围缩小到更小的区间[0.995,1.007]。然后再将此间隔划分为500个值并重复循环。重复,直到达到所需的精度。
在数学上,您希望在函数f: search -> power
的给定间隔内找到计算给定power
参数的某个search
值的最大值。请注意,这通常更容易使您的函数f
更顺畅。为了了解f
的外观,您可以根据循环中计算的值绘制函数。
如果你的功能表现良好并且说是单峰(只有一个“驼峰”),那么例如一个简单的golden section search就会有效。
答案 1 :(得分:1)
这是一个快速的JavaScript代码段/伪代码,可帮助您解决问题。基本上,如果你发现增量/斜率从正到负切换,你的函数应该递归调用。
function findMax(low, high) {
var maxOut = Number.MIN_VALUE;
// Calculate a step based on the low and high
// Using a power of 2 since the floating point numbers are represented by binary
var step = Math.abs((high - low) / 128);
// we'll be tracking the deltas of two test values
var prevDelta;
var delta;
// loop and check two values at a time
for(var i=low; i<=(high - step); i+=step) {
// coef ...
// design ...
// for testing
var out1 = Math.cos(i);
var out2 = Math.cos(i + step);
// update the max
if(out1 > maxOut) maxOut = out1;
if(out2 > maxOut) maxOut = out2;
// calc delta
delta = out2 - out1;
if(prevDelta !== undefined) {
// If one delta is going up and
// another is going down...
// Recursively call the function
if(prevDelta > 0 && delta < 0) {
var out3 = findMax(i - step, i + step);
// update the max
if(out3 > maxOut) maxOut = out3;
}
}
prevDelta = delta;
}
return maxOut;
}
alert(findMax(-0.5, 0.5)); // returns 1
这里是JSFiddle http://jsfiddle.net/hw5f2o1s/
如果最大值位于初始低位和低位+步之间,则上述方法不会起作用,因为递归是通过达到峰值然后从其下降来触发的。如果发生这种情况,您可能需要通过增加两个除以(高 - 低)的功率来使步变量更小。
答案 2 :(得分:0)
浮点数的精度有限(它们是谨慎的),期望偏差。
答案 3 :(得分:0)
当前方向
数字1.0
似乎很重要,可能代表default
。重新编写代码以包含1.0
作为$search
的一部分,将其作为同一循环的一部分或作为单独的迭代注入。