提问人:BlaiseWhite 提问时间:8/9/2023 最后编辑:jaredBlaiseWhite 更新时间:8/9/2023 访问量:97
求解具有一个变量的方程的特定结果
Solving for a specific result to an equation with one variable
问:
如果我想求解一个方程的特定结果,而方程有一个变量可以增加或减少来求解我想要的结果,我该怎么做?
我最初被建议使用二分算法,但在进一步研究后,我发现它仅适用于 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
答:
这个问题是线性的,可以很容易地用手解决。解析解为 。在本例中,该值为 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_h
beta_h1
- 为了提高速度,您可以预先计算,因为内部的值在整个问题中不会更改(至少对于您共享的代码不会更改)。我在上面的代码中做到了这一点。
min(...)
评论
sol.x[0]
假设你的函数实际上等于 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。它还具有安全功能,如果它检测到我们在 的值之间循环(就像您遇到的那样),它会停止。让我们来测试一下:go
x
f(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 - 70
x = i/prec
__getitem__
i
prec
>>> 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
评论