【问题标题】:How to retrieve the max value of a function output如何检索函数输出的最大值
【发布时间】:2021-12-12 17:45:40
【问题描述】:

我有一个函数 f(x)。我想计算 x 其中 f(x) = max。我怎样才能在脚本中做到这一点?

给定: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

}

EDIT2:我的改进版效果很好,但肯定不完美:

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:我还应该提到,当 0

【问题讨论】:

  • 没有作业 :) 我尝试从 x = 1 开始,然后 x *=2。如果 f(x) 小于最后一个结果,我将 x 设置回 x/4。示例:f(16) = 9, f(32) = 11, f(64) = 10。峰值可以在 x=16 和 x=64 之间。所以我的新起点是 f(16)。从那里开始,我想继续,但不确定如何。
  • f 连续吗?
  • 是的,它是连续的。
  • 所以你知道有一个峰值,它是在x 大于1 的时候?
  • 不一定。我实际上简化了我的功能。该函数也有其他输入参数,但它们对我的情况无关紧要。重要的是解决问题的一般方法。该函数只能返回负值,在这种情况下,结果并不有趣。我只对返回正值的场景感兴趣。在这种情况下,我想找到最大值和相应的 x。不需要找到确切的最大值,在一定的迭代限制内最接近就足够了。

标签: javascript algorithm


【解决方案1】:

如果您知道该函数在给定范围内有一个峰值,并且公差范围内的最接近的值是可以接受的,那么您只需要简单的二进制搜索即可。这里我们将范围默认为整个安全整数范围,但您可以提供自己的 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 循环而不是递归可能会更快。我会把这样的优化留给你。但我会先看看这是否足够快,因为简单的代码更容易使用。

【讨论】:

  • 我会接受这个答案,虽然我还不能测试它,但从代码来看它看起来像我需要的。非常感谢。
【解决方案2】:

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

// 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));

【讨论】:

  • Aleksandr 也不要删除这个! :) 感谢您的意见。问题是,没有固定的输入参数列表。就我而言, args 是一个包含所有可能数字的数组。或者,如果你想有一个上限,可以说 1 到 100000 之间的所有有理数。你的算法可能有效,但我认为这需要永远。也许看看我第二次编辑中的代码,以更好地理解我遇到的问题。我试图以指数方式找出最大值在哪里。如果 y 小于 lasty,我会从最后一个 x 重新开始,但减少步数,依此类推。
【解决方案3】:

假设你想最大化 y,你可以只存储 xy 最高的 x 和 y 值:

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);

【讨论】:

  • 谢谢,这是个好主意,它启发了我刚刚在主题的第二次编辑中发布的当前版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-09
  • 2017-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多