您可以继续使用所谓的“二分搜索”技术
这是解决问题的关键。实际上它是的解决方案。让我画两个函数:
f(x) g(x)
/ --
/ --
/ --
/ --
/--
-*
--/
-- /
-- /
^ ^
| |
xlow xhigh
您有xlow 和xhigh 作为f(x) 与g(x) 交叉位置的估计值。在您的问题中,f(x) = ax 和 g(x) = sin(x)。
首先,让我们看看为什么xlow 和xhigh 做出了很好的估计。如果您注意到,在xlow,我们有f(x) < g(x),在xhigh,我们有f(x) > g(x)。由于函数是连续的,因此在f(x) == g(x) 之间存在某个点。
现在让我们看看xlow 和xhigh 之间的中间点:
f(x) g(x)
/ --
/ --
/ --
/ --
/--
-*
--/
-- /
-- /
^ ^ ^
| | |
xlow xmid xhigh
现在在xmid,我们有f(x) > g(x)(在这个例子中)。所以:
f(xhigh) > g(xhigh)
f(xmid) > g(xmid)
f(xlow) < g(xlow)
由于在xmid 和xlow 之间,函数会发生更大的变化(换句话说,f(x) - g(x) 会改变它的符号),那么答案肯定是在xlow 和xmid 之间(注意xmid 和 xhigh 之间仍然可能存在偶数个解决方案,但我们目前无法确定)。
所以,如果我们分配xhigh = xmid,我们将:
f(x) g(x)
/--
-*
--/
-- /
-- /
^ ^
| |
xlow xhigh
但这和以前的问题一样!除了我们将解决方案的可能位置缩小了一半。重复我们有:
f(x) g(x)
/--
-*
--/
-- /
-- /
^ ^ ^
| | |
xlow xmid xhigh
f(xhigh) < g(xhigh)
f(xmid) > g(xmid)
f(xlow) > g(xlow)
这一次,f(x) - g(x) 的符号在xmid 和xhigh 之间变化,所以我们会做xlow = xmid 来切除我们不感兴趣的范围的前半部分。我们得到:
f(x) g(x)
/--
-*
--/
^ ^
| |
xlow xhigh
同样的问题,只是我们将解决方案的可能范围缩小了一半。
在 while 循环中重复此操作,在某些时候|f(xmid) - g(xmid)| 几乎为零(比如小于 0.000001(或 1e-6)(另请注意绝对值))。在这种情况下,我们停止搜索并说那个特定的xmid 就是答案。 (请参阅 here 了解为什么我们不检查相等性,而是检查接近性)。
还有一个问题。对于您的特定功能,可能会有许多横截面。我们如何找到xlow 和xhigh?好吧,我们希望[xlow, xhigh] 范围只包含一个解决方案。所以我们可以逐步找到这些范围并找到它们之间的横截面。
假设a > 0(以及x > 0 的解决方案),图表将如下所示:
----- f(x) = ax
_ _ __*__ _ g(x) = sin(x)
/ \ /_*___----- / \ /
/ *____---*- \ / \ /
|---- | | | | | |
| | | | | |
\ / \ / \ /
\_/ \_/ \_/
那么让我们看看解决方案在哪里。当然,这不是sin(x) < 0。然后在[2kπ, 2kπ + π/2] 和[2kπ + π/2, 2kπ + π] 上可能各有一个解决方案。最初的[0, π / 2] 可能有也可能没有解决方案,具体取决于a。所以最安全的方法是枚举所有这些范围,计算f(x) - g(x) 的xlow 和xhigh 并查看它们的符号。如果标志没有改变,就没有解决方案,我们可以继续前进。如果它确实改变了,我们执行上面的二进制搜索。
算法什么时候结束?我们知道g(x) = sin(x) <= 1 并且我们知道对于a > 0,f(x) = ax 总是在增加。所以当你有f(xlow) > 1,那么肯定没有更多的解决方案了。
因此算法将是:
Main Algorithm:
for k = 0,1,...
xlow = 2kπ
xhigh = 2kπ + π/2
binary_search(xlow, xhigh)
xlow = 2kπ + π/2
xhigh = 2kπ + π
binary_search(xlow, xhigh)
binary_search:
if axlow-sin(xlow) and axhigh-sin(xhigh) have the same sign
return no result in this range
do
xmid = (xhigh + xlow) / 2
diff = axmid - sin(axmid)
if diff and axlow-sin(xlow) have the same sign
xlow = xmid
else
xhigh = xmid
while abs(diff) > epsilon
return xmid
对于a < 0 的情况,解决方案类似(除了范围更改为sin 循环的另一半)。顺便说一句,对于您在上面找到的每个x,-x 也是一个解决方案!