【问题标题】:Recursive Function Help (Python)递归函数帮助 (Python)
【发布时间】:2014-03-07 22:12:25
【问题描述】:

好的,我用递归函数做了一个函数,如下。

global totalExposure
totalExposure = 0 

def f(x):
    import math
    return 10 * math.e**(math.log(0.5)/5.27 * x)

def radiationExposure(start, stop, step):

    time = (stop-start)
    newStart = start+step

    if(time!=0):
        radiationExposure(newStart, stop, step) 
        global totalExposure
        radiation = f(start) * step
        totalExposure += radiation
        return totalExposure
    else:
        return totalExposure

现在,当我输入整数值时,该函数可以正常工作。

rad = radiationExposure(0, 5, 1)
# rad = 39.1031878433

但是,当我输入小数时,我的函数给出了错误的值。 那么,如何让我的函数也可以使用小数呢?

例如:

rad = radiationExposure(0, 4, 0.25)

您的输出: 1217.5725783047335 正确的输出: 1148.6783342153556

【问题讨论】:

  • 你期望输出是什么,输出有什么问题?
  • 只是提示,您应该将import 放在开头,这样就不会在每次函数运行时都调用它...
  • @aj8uppal 无论语句运行多少次,实际只会发生一次导入。 Python 不会重新导入已经导入的模块。
  • 不,我收到70.7212242558
  • 在递归函数中使用全局变量有点错过递归点。

标签: python recursion


【解决方案1】:

我最初回答是floordiv 的错,然后我认为是浮点数作弊,现在我认为这只是糟糕的代码。让我们再深入一点,好吗?

首先,如果您在代码中看到global,请非常努力地摆脱它。它总是会导致这样的错误代码。让我们在没有global....的情况下重写它。

import math

def f(x):
    return 10 * math.e**(math.log(0.5)/5.27 * x)

def radiationExposure(start, stop, step):
    totalExposure = 0
    while stop-start > 0:
        totalExposure += f(start)*step # I dont' know this formula, but this
                                       # feels wrong -- maybe double check the
                                       # math here?
        start += step
    return totalExposure

这实际上也设法摆脱了递归,这将节省大量内存。

### DEMO ###
>>> radiationExposure(0,5,1)
39.10318784326239
>>> radiationExposure(0,4,0.25)
31.61803641252657

我看到的问题是您的global 被保存在函数的递归和调用之间。当我第一次运行你的代码时,我得到了:

>>> radiationExposure(0,5,1)
39.10318784326239
>>> radiationExposure(0,5,1)
78.20637568652478

这显然是错误的。更不用说,递归公式应该调用自己,但它们倾向于在 return 语句中这样做!递归地写这个是这样的:

def radiationExposure(start, stop, step):
    time = stop-start
    new_start = start+step
    radiation = f(start)*step
    if time <= 0: # <= accounts for something like (0, 3, 0.33) where it will never EXACTLY hit zero
        return radiation
        # if we're on the last tick, return one dose of radiation
    else:
        return radiation + radiationExposure(newStart,stop,step)
        # otherwise, return one dose of radiation plus all following doses

【讨论】:

  • 这是一个微分方程的欧拉积分方法,这里它只是函数 f(x) 的积分,或者(平凡的)微分方程 y'(x)=f(x) .应该补偿if time &lt;= 0: 中时间可能大大低于零的情况,因此在这种情况下应该返回f(start)*time 而不是f(start)*step。然后可以将条件更改为if time &lt;= step:,以便最后一个积分步骤恰好落在stop,而不会出现过冲和倒退。
【解决方案2】:

首先纠正的欧拉积分方法保证真正从开始到停止积分,并且确实在停止-epsilon处添加一个额外的积分点(大小步长,将积分间隔更改为在停止+步长处结束)如果浮点对这种情况的错误总结。

回想一下,微分方程 y'(x)=f(x,y(x)), y(x0)=y0 的欧拉积分是通过重复计算进行的

y=y+h*f(x,y)
x=x+h

在纯积分问题中 f 中没有 y,将 f(x) 从 a 积分到 b 从而初始化 y=0 并重复应用

y=y+h*f(x)
x=x+h

只要 x 小于 b。在最后一步中,当 b-h

import math

def f(x):
    return 10 * math.exp(math.log(0.5)/5.27 * x)

def radiationExposure(start, stop, step):
    totalExposure = 0
    while stop-start > 0:
        if stop-start < step:
            step = stop-start;

        totalExposure += f(start)*step 

        start += step
    return totalExposure

if __name__ == "__main__":
    print radiationExposure(0,5,1);
    print radiationExposure(0,5,0.25);
    print radiationExposure(0,5,0.1);
    print radiationExposure(0,5,0.01);

更好的解决方案是使用 numpy 的数值积分例程。


或者更好的是,使用这个函数 f(x)=C*exp(A*x) 的积分实际上是通过反导数 F(x)=C/A*exp(C*A) 知道的,使得值为R(start,stop)=F(stop)-F(start),所以

import math

def radiationExposure2(start, stop, dummy):
    A=math.log(0.5)/5.27;
    C=10
    return C/A*(math.exp(A*stop)-math.exp(A*start))

if __name__ == "__main__":
    print radiationExposure2(0,5,1);
    print radiationExposure2(0,5,1);

返回值用于欧拉积分

39.1031878433 (step=1)
37.2464645611 (step=0.25)
36.8822478677 (step=0.1)
36.6648587685 (step=0.01)

相对于精确积分的数值

36.6407572458

【讨论】:

    猜你喜欢
    • 2011-06-21
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    • 2013-10-31
    • 2010-11-21
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    相关资源
    最近更新 更多