【问题标题】:Algorithm for computing base-10 logarithm in Python在 Python 中计算以 10 为底的对数的算法
【发布时间】:2018-03-18 23:34:38
【问题描述】:

我尝试创建一个程序,根据“数学函数计算手册”中描述的基于泰勒级数的算法计算以 10 为底的对数(我通过我的大学图书馆找到了在线副本)。

StackOverflow 上的另一个问题给出了类似的算法,我现在找不到链接。

10.3.2 计算以十进制为底的对数

对于十进制底,以 10 为底的对数是自然选择,并且将参数分解为 指数和分数为我们提供了十进制表示: x = (−1)^s × f × 10^n,要么 f = 0,要么 f 在 [1/10, 1) 中。

如果 f ≤√1/10,设 f = 10 × f 和 n = n - 1,使得 f 现在在区间 (√1/10,√10] 内。然后引入变量的变化,a泰勒级数展开,以及该展开的多项式表示:

z = (f - 1)/( f + 1),

f = (1 + z)/(1 - z),

D = 2 log10(e)

= 2/log(10)

log10( f) = D × (z + z3/3 + z5/5 + z7/7 + z9/9 + z11/11 + · · · )

≈ D × z + z3Q(z2),多项式拟合将 D 包含在 Q(z2) 中。

对于 (√1/10,√10] 中的 f,我们的 z 大约在 [−0.5195,+0.5195] 范围内。与二进制情况相比,z 的范围更广需要更长的多项式,并且还使得校正项 z3Q (z2) 相对较大。它的大小不超过 |0.35z|,因此它只提供一个额外的十进制数字,而不是两个。z 的精确计算比二进制情况更容易:只需设置 z = fl(fl (f−12)−12)/fl(f+1)。

为此,我用 Python 编写了这个程序:

def log10(x):

n = 0.0 #Start exponent of base 10

while (x >= 1.0):
    x = x/10.0
    n+=1


# if x <= sqrt(1/10)
if(x<=0.316227766016838):
    x = x*10.0
    n = n-1

#Produce a change of variable
z = (x-1.0)/(x+1.0)
D = 4.60517018598809 #2*log10(e)

sum = z
for k in range(3,111,2):
    sum+=(z**k)/k

return D*n*sum

我将结果与math.log10函数进行了比较,结果并不如预期。调试时我最大的问题是理解算法及其工作原理。

【问题讨论】:

  • 我看到了一些小错误。 n可以变成0吗?在这种情况下,Dnsum 看起来像正确的表达式吗?并且 2*log10(e) 不是你在代码中的数字。
  • 如果你试图让 x 进入(sqrt(1/10), 1) 的范围,你不应该在下限上花一点时间,就像在上限上一样吗?此外,您引用的算法指定了(sqrt(1/10), sqrt(10)] 的边界;你在用不同的吗?
  • D*n*sum 的最后一步不能正确使用n。这意味着(sqrt(1/10), 1) 中每个值的对数都是 0。大概你应该将它相加,而不是相乘?
  • @ArndtJonasson 感谢您指出 2*log10(e) 的错误值。我在 Excel 中计算时一定打错了。我已将其更改为0.868588964。 @abarnert你是绝对正确的。应添加 n 术语。我已将返回语句更改为return D*sum+n。关于您对下限的评论,我相信f 变量太小的问题已经由if(x&lt;=0.316227766016838) 语句处理。我现在正在调试程序,但是通过这两个修复程序看起来好多了。谢谢!
  • @abarnert 我现在明白你的意思了。将 if 语句更改为 while 语句。

标签: python algorithm math elementary-functions


【解决方案1】:

这是我在建议更正后的源代码(将返回语句更改为D*sum+n 修复了D 的值,并将if(x&lt;=0.316227766016838) 更改为while(x&lt;=0.316227766016838)。我添加了一些if 语句来处理异常情况。

下面的代码在我的 6 位目标精度范围内运行良好(我用非常小的输入、大输入对其进行了测试)。

def log10(x):

    # Handle exceptional cases
    if (x == 1):
        return 0
    if (x == 0):
        return float('-Inf')
    if (x < 0):
        return float('nan')

    n = 0 #Start exponent of base 10

    while (x >= 1.0):
        x = x/10.0
        n+=1

    # if x <= sqrt(1/10)
    while(x<=0.316227766016838):
        x = x*10.0
        n = n-1

    #Produce a change of variable
    z = (x-1.0)/(x+1.0)
    D = 0.868588964 #2*log10(e)

    #Taylor series
    sum = z
    for k in range(3,23,2):
        sum+=(z**k)/k

    return D*sum+n

【讨论】:

  • 你的代码在第一行之后有明显的缩进错误。
  • @AncoraImparo 我在运行它时没有收到缩进错误。
  • 是的,你重新编辑了。您的原始答案没有缩进。
  • 那么,这是否适用于一系列值(在您的近似值的预期误差范围内)?如果是这样,恭喜。现在编辑答案来解释这一点,并解释你做了什么以及为什么(人们不应该阅读 cmets 来理解答案,特别是因为 cmets 偶尔会被删除)。然后你可以接受你自己的答案,你会帮助未来的求职者并获得一些代表点。
  • @abarnert 很棒。更新了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
  • 2018-10-24
  • 2011-03-19
  • 2023-01-10
  • 2015-01-12
  • 2016-05-20
相关资源
最近更新 更多