如何检索函数输出的最大值



有一个函数f(x)。我想计算f(x) = max时的x。我如何在脚本中做到这一点?

给定x为正数,f(x)可正可负。我想从x = 1开始。如果f(1)已经是负的,我就不感兴趣了。随着x的增加,f(x)也返回增加的值,直到达到峰值,然后f(x)减小。x的峰值是我感兴趣的。

编辑:好的,我到目前为止尝试了什么:

我尝试从x = 1开始,然后x *=2。如果f(x)小于最后一个结果,我将x设为x/4。

示例:f(16) = 9, f(32) = 11, f(64) = 10。峰值可以在x=16和x=64之间。新的起点是f(16)从那以后,我想以类似的方式继续,但我找不到一个算法。

这是我到目前为止得到的:

let x = 1
let lasty = 0
let holder = 1
while (iteration++ < 20) {   

let y = myFunction(x)
if(y < lasty ) {
x = x / 4   
holder = 1         
}          

x += holder * 2  
holder += 1     
lasty = y
}

编辑2:我的改进版本,工作得很好,但肯定不是完美的:

let x = 1
let lasty = 0  
let iteration = 0 
let previousX = 1
let lastX = 1
let step = 2
let maxY = -Infinity
let bestX = 0
let randomInput = Math.random
while (iteration++ < 20) {    
let y = myFunction(x, randomInput) //added randomInput to show the function does not rely on x alone

if (y < 0 && iteration == 1) break  
if(y > maxY) {
maxY = y
bestX = x
}
if (y < lasty) {
x = previousX
step *= 0.8
lasty = 0
} else {
previousX = lastX
lastX = x
x = x * step 
lasty = y
}
}
if(bestX > 0) {
console.log(`Got best x: ${bestX}`)
}

EDIT3:添加随机附加参数以强调所需的方法

EDIT4:我还应该提到,f(x) = max的概率在0

假设您想最大化y,您可以将x和y值存储在xy最高的地方:

let highestX = 1; // this is just the corresponding x value for the highest y
let highestY = -Infinity;
let x = 1
let lasty = 0
let holder = 1
while (iteration++ < 20) {   

let y = myFunction(x);
// code for storing the highest y and corresponding x
if (y > highestY) {
highestY = y;
highestX = x;
}
if(y < lasty ) {
x = x / 4   
holder = 1         
}          

x += holder * 2  
holder += 1     
lasty = y
}
console.log('f(x) is maximised when x =', highestX);

如果您知道函数在给定范围内只有一个峰值,并且在公差范围内最接近的值是可以接受的,那么您应该只需要一个简单的二进制搜索。在这里,我们默认的范围是整个安全整数范围,但是你可以提供你自己的findPeak (tolerance) (fn, rangeMin, rangeMax),也许像findPeak (1e-8) (fn, 0, 100000)

const findPeak = (ε) => (
fn, 
min = Number.MIN_SAFE_INTEGER, 
max = Number.MAX_SAFE_INTEGER, 
mid = min / 2 + max / 2
) => 
max - min < ε
? mid
: fn (min) < fn (max)
? findPeak (ε) (fn, mid, max)
: findPeak (ε) (fn, min, mid)
const fn = n => 600 + 50 * n - n ** 2
console .log (findPeak (1e-8) (fn)) //=> 24.99999991050572

这个代码很简单。如果我们利用在每个后续调用中重用fn (min)fn (max)的事实,那么它的效率可能会降低,并且使用while循环可能比递归更快。我将把这种优化留给您。但我想先看看这是否已经足够快了,因为简单的代码更容易使用。

可以使用递归函数调用来解决。

// array of arguments
const args = [...Array(16).keys()];
// sample function
const sampleFunc = (x) => Math.sin(x);
// recursive function
function getElementWithFuncMaximum(arr, func, index = 0, currValue = 0) {
const currFuncValue = func(arr[index]);
return currFuncValue >= currValue 
? getElementWithFuncMaximum(arr, func, index + 1, currFuncValue)
: arr[index - 1];
}
console.log(getElementWithFuncMaximum(args, sampleFunc));

最新更新