当前位置: 首页 > 知识库问答 >
问题:

阶乘函数在Python中工作,为Julia返回0

宇文飞羽
2023-03-14

我在Python中定义了一个阶乘函数,如下所示:

def fact(n):
    if n == 1:
        return n
    else:
        return n * fact(n-1)

print(fact(100))
function fact(n)
    if n == 1
        n
    else
        n * fact(n-1)
    end
end

println(fact(100))

python程序返回一个非常大的数值,计算值为100(如预期的那样)。朱莉娅返回0。对于较小的数字(如10),它们都起作用。

我有两个问题:

  1. 为什么Python可以处理这个问题,而Julia不能。
  2. 为什么Julia不抛出错误而只打印0?

共有1个答案

古彦
2023-03-14

Julia有独立的固定大小的整数类型,外加一个BigInt类型。默认类型是int64,当然是64位。

从100岁开始!大约需要526位,它显然溢出了int64

您可以通过执行fact(BigInt(100))(假设您需要d it)来解决这个问题,当然也可以在fact函数中执行转换。

Python曾经也是一样,很久以前。它有单独的类型intlong,前者是16位、32位或64位,这取决于您的机器,后者是任意长度的。如果您在Python 1.5上运行您的程序,它要么像Julia一样绕圈,要么引发异常。解决方案是调用fact(100L),或者在fact函数中执行到long的转换。

但是,在2.x系列中的某个时候,Python将这两种类型绑定在一起,因此任何溢出的int都会自动变成long。然后,在3.0中,它完全合并了这两种类型,因此不再存在单独的long

那么,为什么Julia只是溢出而不是引发错误呢?

FAQ实际上解释了为什么Julia使用本机整数算法。其中包括溢出时的环绕行为。

人们所说的“原生机器算术”通常指的是“C在几乎所有2s-补码机器上所做的事情”。尤其是在像Julia和Python这样的语言中,这些语言最初构建在C之上,并且非常接近于金属。在朱莉娅的案例中,这不仅仅是“默认”,而是一种有意的选择。

在C语言中(至少在当时是这样),如果溢出有符号整数类型(如int64)会发生什么实际上取决于实现……但是在几乎所有本地使用2的补码算术的平台上(几乎是您今天看到的任何平台),发生了完全相同的事情:它只是截断顶部64位以上的所有内容,这意味着从正到负。事实上,无符号整数类型在C中需要这样工作。(同时,C也是这样工作的,因为大多数CPU都是这样工作的。)

在C语言中(与大多数CPU的机器语言不同),没有办法检测到您已经得到了溢出。因此,如果要引发OverflowError,则必须编写一些逻辑,在执行乘法之前检测乘法将溢出。你必须在每一个乘法上运行这个逻辑。您可以通过编写内联汇编代码对某些平台进行优化。或者您可以强制转换为更大的类型,但是(a)这会使代码更慢;(b)如果您已经使用了最大的类型(int64,今天在许多平台上都有),这就不起作用了。

在Python中,使每次乘法速度慢4倍(通常会慢一些,但也可能那么高)并没有什么大不了的,因为Python在获取字节码和解封整数对象上花费的时间比乘法要多。但朱莉娅注定要比这更快。

正如约翰·迈尔斯·怀特在《计算机是机器》中所解释的那样:

在许多方面,Julia将自己与其他新语言区别开来,它试图恢复从C到Python等语言转换过程中失去的一些能力。但这种转变伴随着一个实质性的学习曲线。

但还有另一个原因:溢出符号算术在许多情况下确实有用。没有溢出的无符号算术那么多(这就是为什么C在第一个ANSI规范之前就定义了无符号算术来这样工作),但是有一些用例。

而且,即使您想要类型转换的次数可能比想要翻转的次数多,手动进行类型转换要比翻转容易得多。如果您曾经在Python中这样做过,选择%的操作数并正确地获得符号肯定很容易出错;转换为bigint是很难搞砸的。

最后,在强类型语言中,比如Python和Julia,类型稳定性很重要。Python 3存在的原因之一是旧的str类型神奇地转换为Unicode导致了问题。int类型奇迹般地转换为long导致问题的情况要少得多,但这种情况可能会发生(例如,当您从线上或通过C API获取一个值,并期望以相同的格式写入结果时)。Python的开发团队在统一int/long时对此进行了争论,引用了“实用性胜过纯洁性”和Zen的各种其他部分,并最终决定旧行为比新行为引起的问题更多。朱莉娅的设计做出了相反的决定。

 类似资料:
  • 本文向大家介绍Julia命令式阶乘,包括了Julia命令式阶乘的使用技巧和注意事项,需要的朋友参考一下 示例 长格式语法可用于定义多行功能。当我们使用命令式结构(例如循环)时,这很有用。返回尾部位置的表达式。例如,下面的函数使用for循环来计算某个整数的阶乘n: 用法: 在较长的函数中,通常会看到所return使用的语句。该return语句在尾部位置不是必需的,但有时仍为清楚起见而使用。例如,编写

  • 有没有可能创建一个函数,它将lambda函数作为参数(每个lambda函数使用参数),然后返回一个具有单个参数的新函数,并返回所有lambda函数的乘积? 以下是我的非工作示例: 所以本质上,你有一个函数,它需要4个lambda函数,每个函数使用参数。例如,的参数可以类似于。 然后返回一个名为的新函数,该函数的输出是所有lambda函数的乘积,并且有一个参数,该参数传递到的每个lambda函数的参

  • 我正从最基本的方面着手研究递归,因为我在过去很挣扎。我在看这个阶乘解: 因此函数会一直调用自己,直到<code>n==0</code>为止。然后在每次调用时返回值。这就是我不明白的:当它从基本条件返回时,它返回一个值,并不断添加每个调用的值。 这些值存储在哪里,以便最终能够返回总和?

  • 问题内容: 我认为我完全理解这一点,但我只是想确保,因为我总是看到人说要 永远 对测试,或。 他们建议例程应引发错误,而不是返回False或None。无论如何,在很多情况下,我只是想知道是否设置了标志,所以我的函数返回True或False。在其他情况下,如果没有有用的结果,我将有一个函数返回None。根据我的想法,只要我意识到我永远都不要使用: 而是应使用: 因为True,False和None都是

  • 问题内容: 在python中编写函数非常简单: 不幸的是,当想要使用组合作为 键时 ,这有点of脚: 这实际上应该只是,因为该函数无论如何都不会用于其他任何事情: 好吧,那就定义它吧! 天哪! 天哪! 嘿,现在我们到了某个地方。 但是我不想上课!在我不完全了解的范围内,作用域规则完全不同,这甚至比“ lameda”还要丑。我想对这些 功能 进行修补。我怎样才能做到这一点? 问题答案: 尽管您可能希

  • Python3 实例 整数的阶乘(英语:factorial)是所有小于及等于该数的正整数的积,0的阶乘为1。即:n!=1×2×3×...×n。 #!/usr/bin/python3 # Filename : test.py # author by : www.runoob.com # 通过用户输入数字计算阶乘 # 获取用户输入的数字 num = int(input("请输入一个数字: ")) fa