【发布时间】:2020-10-02 22:14:51
【问题描述】:
总之,我试图从给定的x 开始,并在正方向上找到f(x) = 0 的最近点。为简单起见,仅在区间 [initial_x, maximum_x] 中需要解决方案(已给出最大值),但任何更好的范围都是可取的。此外,特定的精度不是强制性的;我希望最大化它,但不以性能为代价。
虽然这看起来很简单,但有一些注意事项会使解决方案变得更加困难。
- 性能是第一要务,甚至高于某些精度。需要在对
f(x)的尽可能少的调用中找到零,因为此代码每秒会运行多次。 - 不保证此行中包含任何特定数量的零。函数与 x 轴相交的位置可能有 0 个、1 个或多个。 (这就是为什么直接二分查找不起作用的原因。)
- 函数
f(x)不能代数操作,只支持离散点的数值计算。 (这就是无法通过分析找到解决方案的原因。)
我目前的策略是定义一个在可接受的精度损失范围内的步长,然后以增量进行测试,直到找到一个保证至少有一个零的区间(在 [a,b] 中,a和 b 在 0) 的对边。从那里,我使用二进制搜索来缩小(更多)确切点。
// assuming y != 0
initial_y = f(x);
while (x < maximum_x) {
y = f(x);
// test to see if y has crossed 0
if (initial_y > 0) {
if (y < 0) {
return binary_search(x - step_size, x);
}
} else {
if (y > 0) {
return binary_search(x - step_size, x);
}
}
x += step_size;
}
这有几个缺点,主要是分辨率和性能之间需要权衡取舍(step_size 越小,效果越好,但需要的时间越长)。我可以采取更有效的公式或策略吗?我想过使用y 的值来缩放步长,但我不知道如何在这样做时保持精度。
解决方案可以是任何语言,因为我更多的是寻找找到零的策略,而不是特定的程序。
(编辑:)
上面的函数假设是连续的。
为了澄清这个问题,我知道这个问题可能无法完全解决。我只是在寻求提高算法速度或精度的方法。我目前使用的那个运行良好,尽管它在许多边缘情况下都失败了。
例如,需要较少步数且精度相似的解决方案,或另一种提高精度或可靠性但对性能有一定影响的算法都将非常有帮助。
【问题讨论】:
-
你的策略是明智的,但它不能保证你会找到 first 根(即使在给定的容差内),因为你会跳过间隔偶数个根。不知道您通常可以做得更好,至少对目标功能有所了解。考虑一个完全任意函数可能是一个“病态”函数,例如
sin(1/x)或floor(1/x) mod 10,在您开始的点附近有无数个零。 -
这就是问题所在。本质上,我正在使用用户创建的函数,所以我不能保证它会以任何特定的方式运行。而且,我明白你在说什么,这就是我寻求改进的原因。当前的实现有很多错误,当函数有很多接近零并且在边缘情况下经常失败。
-
这是不可能解决的。为了得到一些明智的答案,你需要设置一些限制。