求解具有一个变量的方程的特定结果

Solving for a specific result to an equation with one variable

提问人:BlaiseWhite 提问时间:8/9/2023 最后编辑:jaredBlaiseWhite 更新时间:8/9/2023 访问量:97

问:

如果我想求解一个方程的特定结果,而方程有一个变量可以增加或减少来求解我想要的结果,我该怎么做?

我最初被建议使用二分算法,但在进一步研究后,我发现它仅适用于 python 中的平方根方程。

例如

rho1 = 0.177
Nh = 9.3
Nv = 128
Qh = 10
H = 1
beta_h1 = .0000000001
def beta_h_func(beta_h):
     return beta_h1*min(Nv/(Qh*Nh), 1) + rho1*H*min(Nv/(Qh*Nh), 1)
while beta_h_func(beta_h1) != 1:
    if beta_h_func(beta_h1) < 1:
        beta_h1 += .000000001
        beta_h_func(beta_h1)
    if beta_h_func(beta_h1) > 1:
        beta_h1 -= .000000001
        beta_h_func(beta_h1)

其中可用于增加或减少的变量。 但这样做只会导致无限的来回,在 1 的上方和下方永无止境。我可以将 while 函数更改为什么才能获得决定性的 1 作为我的结果。beta_h1

python numpy 数学 sympy ode

评论

1赞 jared 8/9/2023
当你说平分只能用于平方根方程时,你是什么意思?
1赞 jared 8/9/2023
此外,您的结果永远不会正好是 1,因此您不应该检查是否相等。
0赞 Grismar 8/9/2023
您可以在超调后减小步长,但最终会遇到浮点数缺乏精度的问题。你能做的最好的事情就是提出一个值,在你使用的浮点表示中获得最佳结果,但这不一定与数学上的最佳值相同。为此,您需要使用更精确的数字表示形式。但是,根据起始值,用户@jared是正确的,因为您可能永远不会达到正好 1。

答:

1赞 jared 8/9/2023 #1

这个问题是线性的,可以很容易地用手解决。解析解为 。在本例中,该值为 0.823。beta_h1 = (1 - rho1*H*min(Nv/(Qh*Nh), 1))/min(Nv/(Qh*Nh), 1)

假设这只是一个示例,而您的实际问题更复杂,那么您遇到的就是一个寻根问题。为此,您可以使用 scipy.optimize.root 来查找解决方案。Scipy 包含其他寻根方法,包括适用于此问题的二分法(我不确定为什么你说二分法仅适用于平方根问题,无论这意味着什么)。

from scipy.optimize import root

rho1 = 0.177
Nh = 9.3
Nv = 128
Qh = 10
H = 1
c = min(Nv/(Qh*Nh), 1)


def beta_h_func(beta_h1):
    return c*(beta_h1 + rho1*H) - 1


sol = root(beta_h_func, 1)
print(sol)

输出:

 message: The solution converged.
 success: True
  status: 1
     fun: [ 0.000e+00]
       x: [ 8.230e-01]
    nfev: 4
    fjac: [[-1.000e+00]]
       r: [-1.000e+00]
     qtf: [ 3.861e-13]

根据该结果,您的根被给出为(索引为您提供而不是 numpy 数组)。sol.x[0]float

关于您的代码的几条评论。

  • 您的循环可能会永远运行,因为您正在处理浮点数并检查相等性。比较浮点数时,检查它们是否接近(具有一定的容差),不完全相等。while
  • 更新后对函数的评估是无用的,因为这些结果不会发生任何变化。beta_h1
  • 函数的参数是 而不是 。beta_hbeta_h1
  • 为了提高速度,您可以预先计算,因为内部的值在整个问题中不会更改(至少对于您共享的代码不会更改)。我在上面的代码中做到了这一点。min(...)

评论

0赞 BlaiseWhite 8/9/2023
使用 root 后,我将如何从结果中分离 x 变量?
0赞 jared 8/9/2023
@BlaiseWhite我刚刚编辑了我的解决方案以显示它,由你做.sol.x[0]
1赞 smichr 8/9/2023 #2

假设你的函数实际上等于 1,如果你代入正确答案,

>>> def beta_h_func(beta_h):
...      return beta_h*min(Nv/(Qh*Nh), 1) + rho1*H*min(Nv/(Qh*Nh), 1)
...
>>> beta_h_func(.823)==1
True

你的循环逻辑合理吗?让我们在一个更简单的函数上测试它:.f(x) = x - 1

f = lambda x: x - 1

def go(step):
    x = 0
    dir = None
    while (y:=f(x)) != 1:
        if y < 1:
            if dir is None:
                dir = 1
            elif dir == -1:
                return 'looping', x, x+step
            x += step
        elif y > 1:
            if dir is None:
                dir = -1
            elif dir == 1:
                return 'looping', x-step, x
            x -= step
    return(x)

此函数将接受一个步骤并返回 at 的值为 1。它还具有安全功能,如果它检测到我们在 的值之间循环(就像您遇到的那样),它会停止。让我们来测试一下:goxf(x)x

>>> go(1)
2
>>> go(.5)
2.0
>>> go(.25)
2.0

所以逻辑是合理的。让我们尝试一个小步骤......喜欢 0.1

>>> go(.1)
('looping', 1.9000000000000004, 2.0000000000000004)

尽管逻辑对于精确的人工技艺是合理的,但当你处理浮点数时,你不能保证步骤的总和会把你带到函数达到所需值的单个值。在我的例子中,从 0 步进 0.1 使我们略高于 1.9 和略高于 2,但从未达到 2。你的功能(你自己承认)也遭受了同样的命运。(它也因需要将近 100 亿步才能达到循环点而受到影响。

值得您花时间了解如何实现平分,例如,请参阅此处

高级主题

如果您可以根据整数输入编写函数,您甚至可以使用 Python 的内置二分例程。例如,假设我们想找到 的解。然后,让我们定义一个函数类,该函数类具有返回给定函数值的方法,并且还允许您指定以下值:x**2 - 70x = i/prec__getitem__iprec

>>> class f(object):
...   def __init__(self, prec): self.prec = prec
...   def __getitem__(self, i):
...       x = i/self.prec
...       return x**2-70
...
>>> prec = 1000
>>> f(prec)[1*prec]  # 1**2 - 70
-69.0

现在让例程找到 x 的第一个值,该值给出的 f 值为 >= 0:bisect

>>> from bisect import bisect
>>> prec = 10000; bisect(f(prec), 0, 8*prec, 10*prec)/prec  # nearest 1/1000
8.3667
>>> _**2
70.00166888999999
>>> prec = 2; bisect(f(prec), 0, 8*prec, 10*prec)/prec  # nearest half
8.5
>>> _**2
72.25
>>> prec = 2**10; bisect(f(prec), 0, 8*prec, 10*prec)/prec  # nearest 2**-10
8.3671875
>>> _**2
70.00982666015625

评论

0赞 BlaiseWhite 8/10/2023
谢谢,这对我建立对这种情况的理解有很大帮助。我很欣赏这些建议,也教我。
0赞 smichr 8/10/2023
很高兴它有帮助。如果您喜欢该答案,可以通过单击复选符号来“接受”它。