【问题标题】:How to solve this: two functions x = sin(x)/a如何解决这个问题:两个函数 x = sin(x)/a
【发布时间】:2014-03-16 23:13:58
【问题描述】:

我试图以不同的方式解决这个方程,但没有运气:

求两个函数的点数。

f(x) = sin(x)  
y = a  

在给定的a。在这种情况下,让我们说a = 0.15

sin(x) = ax
= 0.15x
x = sin(x)/0.15

???

谁能帮忙解答一下这个问题?

这正是问题所在:

编写一个 C 程序,该程序将读取值 a 并写出方程 sin(x) = a*x 的所有解(即根)

注意:这个方程肯定有一个解:x = 0。然而,对于a 的低值,表示方程y = a*x 的线足够接近水平线以多次穿过正弦波。您的程序应计算并打印根数及其值。

提示:假设您要求解方程f(x) = 0,其中f(x) 是一个连续函数。进一步假设您可以找到两个值xlowxhigh,这样f(xlow) < 0f(xhigh) > 0 以及函数f(x) 在这些值之间的某个位置只穿过x 轴一次。您可以继续使用所谓的“二分搜索”技术,如下所示:

  1. 将解 x 估计为 x = (xlow + xhigh) / 2.0
  2. 如果 |f(x)|
  3. 如果 f(x)
  4. 转到(1)

使用 epsilon = 0.001

【问题讨论】:

  • 您说 $a=.15$,但随后您将方程式中的 $a$ 替换为 $.15x$。这是一个错误吗?
  • @GTonyJacobs 我认为原始方程应该是 $\sin(x)=ax$。
  • "求两个函数的点数。"接下来的内容没有意义。请检查一下。
  • @leonbloy 我认为他的意思是“0.15x 和 sin(x) 的交点”
  • 编辑“this is the question in the exact words...”表明这是一个编程问题。在我看来,它属于 stackoverflow。

标签: c math binary-search


【解决方案1】:

您可以继续使用所谓的“二分搜索”技术

这是解决问题的关键。实际上它的解决方案。让我画两个函数:

           f(x)   g(x)
            /    --
           /   --
          /  --
         / --
        /--
       -*
     --/
   -- /
 --  /

 ^                 ^
 |                 |
 xlow              xhigh

您有xlowxhigh 作为f(x)g(x) 交叉位置的估计值。在您的问题中,f(x) = axg(x) = sin(x)

首先,让我们看看为什么xlowxhigh 做出了很好的估计。如果您注意到,在xlow,我们有f(x) < g(x),在xhigh,我们有f(x) > g(x)。由于函数是连续的,因此在f(x) == g(x) 之间存在某个点。

现在让我们看看xlowxhigh 之间的中间点:

           f(x)   g(x)
            /    --
           /   --
          /  --
         / --
        /--
       -*
     --/
   -- /
 --  /

 ^        ^        ^
 |        |        |
 xlow     xmid     xhigh

现在在xmid,我们有f(x) > g(x)(在这个例子中)。所以:

f(xhigh) > g(xhigh)
f(xmid)  > g(xmid)
f(xlow)  < g(xlow)

由于在xmidxlow 之间,函数会发生更大的变化(换句话说,f(x) - g(x) 会改变它的符号),那么答案肯定是在xlowxmid 之间(注意xmidxhigh 之间仍然可能存在偶数个解决方案,但我们目前无法确定)。

所以,如果我们分配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) 的符号在xmidxhigh 之间变化,所以我们会做xlow = xmid 来切除我们不感兴趣的范围的前半部分。我们得到:

       f(x)  g(x)
         /--
       -*
     --/

      ^    ^
      |    |
      xlow xhigh

同样的问题,只是我们将解决方案的可能范围缩小了一半。

在 while 循环中重复此操作,在某些时候|f(xmid) - g(xmid)| 几乎为零(比如小于 0.000001(或 1e-6)(另请注意绝对值))。在这种情况下,我们停止搜索并说那个特定的xmid 就是答案。 (请参阅 here 了解为什么我们不检查相等性,而是检查接近性)。


还有一个问题。对于您的特定功能,可能会有许多横截面。我们如何找到xlowxhigh?好吧,我们希望[xlow, xhigh] 范围只包含一个解决方案。所以我们可以逐步找到这些范围并找到它们之间的横截面。

假设a &gt; 0(以及x &gt; 0 的解决方案),图表将如下所示:

                              ----- f(x) = ax
   _           _         __*__         _ g(x) = sin(x)
  / \         /_*___----- / \         /
 /   *____---*-  \       /   \       /
|---- |     |     |     |     |     |
      |     |     |     |     |     |
       \   /       \   /       \   /
        \_/         \_/         \_/

那么让我们看看解决方案在哪里。当然,这不是sin(x) &lt; 0。然后在[2kπ, 2kπ + π/2][2kπ + π/2, 2kπ + π]可能各有一个解决方案。最初的[0, π / 2] 可能有也可能没有解决方案,具体取决于a。所以最安全的方法是枚举所有这些范围,计算f(x) - g(x)xlowxhigh 并查看它们的符号。如果标志没有改变,就没有解决方案,我们可以继续前进。如果它确实改变了,我们执行上面的二进制搜索。

算法什么时候结束?我们知道g(x) = sin(x) &lt;= 1 并且我们知道对于a &gt; 0f(x) = ax 总是在增加。所以当你有f(xlow) &gt; 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 &lt; 0 的情况,解决方案类似(除了范围更改为sin 循环的另一半)。顺便说一句,对于您在上面找到的每个x-x 也是一个解决方案!

【讨论】:

  • 搜索“二等分法”会发现命中率更高。确实应该避免这种情况,这是一种相当慢的方法,请在“错误位置方法”或“regula falsi”下查看更快的收敛方法。 -- 此外,还有 a 值,其中线 ax 接近于切线,但仍与 y=sin(x) 的向上弓相交。那么二分法会在搜索区间的终点报同样的符号,错过里面的解。
【解决方案2】:

显然,只能有解决方案

-1 <= ax <= 1

差分函数 h(x)=sin(x)-ax 的单调性在导数 h'(x)=cos(x)-a 的根之间的所有区间上都是相同的,它们也是该函数的局部最大值和最小值。所以用积分

arccos(a), 2*pi-arccos(a), 2*pi+arccos(a), 4*pi-arccos(a), 4*pi+arccos(a), ...

只要它们小于 1/abs(a) 即可定义搜索间隔。根据 Shahbaz 的回答,在它们每个内部使用二分法,或者更好的伊利诺伊变体 regula falsi 方法。

【讨论】:

  • 列表中应该有-arccos(a)吗?
  • 没有。第一个非负解是 x=0。 h(0)=0,并且 h'(x)>0 从 0 到 arccos(a),因此在该段上 h(x)>0。要在 0 和 pi/2 之间找到一个根,需要 a=1-eps 接近 1。然后 arccos(1-eps) 大约是 sqrt(2*eps) 和 sin(x)=sqrt(2*eps-eps^ 2)>a*x=sqrt(2*eps-4*eps^2+2*eps^3) 在那个点,即h(sqrt(2*eps))>0,而下一个点x=2 *pi-sqrt(2*eps) 具有相反的关系,h(x) 约。 -2*pi
  • sin(x) 是一个奇函数,ax 也是如此。我希望x 是解决问题的方法,-x 也是解决方法。 OP 似乎对non-negative solution 没有限制,所以-arccos(a), -2*pi-arccos(a), -2*pi+arccos(a), -4*pi-arccos(a), -4*pi+arccos(a), ... 也是解决方案。
  • 是的,当然,我的印象是所有答案都隐含地理解了这一点。所以让我重申一下:除了 x=0 之外,-arccos(a) 和 arccos(a) 之间没有其他解决方案。而且您不需要检查负区间,因为对于正解,所有负解也是已知的。
【解决方案3】:

没有任何优化的 brutefore 方法(因此是一种幼稚的方法)会在 x 上运行 for 循环,x 从 0 到 2*PI,PI = 22.0/7.0,如果你得到 abs,循环递增 0.001 (sin(x) - a*x)

【讨论】:

  • -1: [0, 2*pi] 之外有解。问题的“注意”中提到了这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-07
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多