Python没有';t运行Euler';宽度小于0.2的s方法?
我对python编码有一个奇怪的问题。我有一个简单的代码,用来执行Euler近似,数值上近似一个微分方程的解。它通过取一段曲线并将其划分为等宽“w”的间隔来实现 代码是:Python没有';t运行Euler';宽度小于0.2的s方法?,python,Python,我对python编码有一个奇怪的问题。我有一个简单的代码,用来执行Euler近似,数值上近似一个微分方程的解。它通过取一段曲线并将其划分为等宽“w”的间隔来实现 代码是: import math x = 0 y = 2 w = 0.5 while x < 1: dydx = 1 - 2*x + y deltaY = dydx*w y = y + deltaY x += w print(x,y) 导入数学 x=0 y=2 w=0.5 当x
import math
x = 0
y = 2
w = 0.5
while x < 1:
dydx = 1 - 2*x + y
deltaY = dydx*w
y = y + deltaY
x += w
print(x,y)
导入数学
x=0
y=2
w=0.5
当x<1时:
dydx=1-2*x+y
deltaY=dydx*w
y=y+deltaY
x+=w
打印(x,y)
奇怪的是,我发现该代码适用于1到1/5之间的“w”,但不会更小
例如,使用w=1/5,代码将正确输出(1.0、5.48832…)
或使用w=1/4。代码正确输出(1.0、5.4414…)
但是如果我使用w=1/6,输出是(1.16667,6.27523…)
我已经为运行Euler的修改方法和Romberg的方法(用于近似相同的事情)的程序改编了相同的代码,并且它们对w<1/5做了相同的事情
我觉得这个问题的答案要么非常明显,要么非常模糊。如果有人有解决办法,我将非常感激
谢谢0.2的截止值只是一个巧合。这里真正发生的是浮点舍入
float
值不能准确表示大多数分数;它们只给你最接近你想要的数字的52位二进制分数。这会导致舍入错误
- 如果将1/2与0相加两次,则正好得到1
- 如果你把1/3和0相加三次,你会得到一个比1大一点点的数字,但是1实际上是最接近这个数字的二进制分数
- 如果将1/4与0相加四次,则正好得到1
- 如果你把1/5和0相加五次,你会得到一个比1大一点的数字
- 如果你把1/6和0相加六次,你会得到一个比1小一点的数字
- 如果你把1/7和0相加七次,你会得到一个比1小一点的数字
- 如果将1/8与0相加四次,则正好得到1
x
稍微大于1时,x<1
为false,循环停止。但是1/6和1/7是不好的,因为当x
比1小一点点时,x<1
仍然是真的,所以循环次数过多了一次
最简单的修复方法是使用
isclose
:
while not math.isclose(x, 1):
…虽然这意味着如果x不是非常接近一元分数,则会有一个无限循环。当然,您的方法不适用于这样的值,但最好是得到一个错误或不正确的结果,而不是等到世界末日。所以你可能想做一些更聪明的事情,比如:
while x < 0.999999:
现在您将获得:
1 5.521626371742112
但最好的选择可能是跟踪
w
是1/6
,如下所示:
import math
x = 0
y = 2
w_inv = 6
w = 1/w_inv
for _ in range(w_inv):
dydx = 1 - 2*x + y
deltaY = dydx*w
y = y + deltaY
x += w
print(x,y)
现在舍入误差不是问题;无论如何,我们肯定要循环6次
0.9999999999999999 5.521626371742112
0.2的截止值只是一个巧合。这里真正发生的是浮点舍入
float
值不能准确表示大多数分数;它们只给你最接近你想要的数字的52位二进制分数。这会导致舍入错误
- 如果将1/2与0相加两次,则正好得到1
- 如果你把1/3和0相加三次,你会得到一个比1大一点点的数字,但是1实际上是最接近这个数字的二进制分数
- 如果将1/4与0相加四次,则正好得到1
- 如果你把1/5和0相加五次,你会得到一个比1大一点的数字
- 如果你把1/6和0相加六次,你会得到一个比1小一点的数字
- 如果你把1/7和0相加七次,你会得到一个比1小一点的数字
- 如果将1/8与0相加四次,则正好得到1
x
稍微大于1时,x<1
为false,循环停止。但是1/6和1/7是不好的,因为当x
比1小一点点时,x<1
仍然是真的,所以循环次数过多了一次
最简单的修复方法是使用
isclose
:
while not math.isclose(x, 1):
…虽然这意味着如果x不是非常接近一元分数,则会有一个无限循环。当然,您的方法不适用于这样的值,但最好是得到一个错误或不正确的结果,而不是等到世界末日。所以你可能想做一些更聪明的事情,比如:
while x < 0.999999:
现在您将获得:
1 5.521626371742112
但最好的选择可能是跟踪
w
是1/6
,如下所示:
import math
x = 0
y = 2
w_inv = 6
w = 1/w_inv
for _ in range(w_inv):
dydx = 1 - 2*x + y
deltaY = dydx*w
y = y + deltaY
x += w
print(x,y)
现在舍入误差不是问题;无论如何,我们肯定要循环6次
0.9999999999999999 5.521626371742112
我猜这是一个浮点精度问题。我不知道你想计算什么,所以我无法详细解释到底发生了什么,但我怀疑你会发现,在某个地方,你应该得到
x==1.0
,但由于四舍五入,你反而得到了一些小数目,这个错误会导致额外的迭代,从而导致错误的输出。您希望浮点和正好落在1上。我猜这是一个浮点精度问题。我不知道你想计算什么,所以我无法详细解释到底发生了什么,但我怀疑你会发现,在某个地方,你应该得到x==1.0
,但由于四舍五入,你反而得到了一些小数目,这个错误会导致额外的迭代,导致错误的输出。您希望浮点和正好落在1上。