Julia 有单独的固定大小整数类型,以及 BigInt 类型。默认类型是Int64
,当然是64位。
从100开始!大约需要526位,它显然溢出了Int64
.
你可以通过这样做来解决这个问题fact(BigInt(100))
(假设你已经require
d 它),或者当然你可以在fact
功能。
曾几何时,Python 也曾经是这样的。它有不同的类型int
,它是 16 位、32 位或 64 位,具体取决于您的计算机,以及long
,这是任意长度的。如果您在 Python 1.5 上运行程序,它要么像 Julia 一样回绕,要么引发异常。解决方案是调用fact(100L)
,或者转换为long
在 - 的里面fact
功能。
然而,在 2.x 系列的某个时刻,Python 将这两种类型捆绑在一起,因此任何int
自动溢出变成long
。然后,在3.0中,它完全合并了这两种类型,因此没有单独的long
不再了。
那么,为什么 Julia 只是溢出而不是引发错误呢?
常见问题解答实际上解释了为什么 Julia 使用本机机器整数运算 http://docs.julialang.org/en/latest/manual/faq/#why-does-julia-use-native-machine-integer-arithmetic。其中包括溢出时的环绕行为。
人们通常所说的“本机机器算术”是指“C 在几乎所有 2 补码机器上所做的事情”。尤其是像 Julia 和 Python 这样最初构建在 C 之上的语言,并且非常接近金属。就 Julia 而言,这不仅仅是一种“默认”,而是一种有意的选择。
在 C 中(至少当时是这样),实际上取决于实现,如果溢出有符号整数类型(例如int64
…但在几乎所有原生使用 2 的补码算术的平台上(几乎是您今天看到的所有平台),都会发生完全相同的事情:它只是截断前 64 位以上的所有内容,这意味着您从正数换到负数。实际上,unsigned整数类型是required在 C 中以这种方式工作。(同时,C 也以这种方式工作,因为这就是大多数 CPU 的工作方式。)
In C (unlike大多数 CPU 的机器语言),没有办法在事后检测到溢出。所以,如果你想提高OverflowError
,您必须编写一些逻辑来检测乘法在执行之前是否会溢出。你必须在每次乘法中运行该逻辑。您可以通过编写内联汇编代码针对某些平台对此进行优化。或者,您可以转换为更大的类型,但是(a)这往往会使您的代码变慢,并且(b)如果您已经在使用最大的类型(其中int64
今天在许多平台上)。
在 Python 中,使每次乘法减慢 4 倍(通常更少,但也可能那么高)没什么大不了的,因为 Python 花费更多时间来获取字节码和拆箱整数对象,而不是乘法。但 Julia 的速度应该比这更快。
正如约翰·迈尔斯·怀特 (John Myles White) 在《计算机是机器 http://www.johnmyleswhite.com/notebook/2013/01/03/computers-are-machines/:
在许多方面,Julia 试图恢复从 C 到 Python 等语言的过渡中失去的一些功能,从而使自己与其他新语言区分开来。但这种转变伴随着巨大的学习曲线。
但这还有另一个原因:溢出有符号算术在许多情况下实际上很有用。几乎没有溢出的那么多unsigned算术(这就是为什么自第一个 ANSI 规范之前 C 就定义了无符号算术以这种方式工作),但也有用例。
而且,即使您可能想要类型转换的频率比想要翻转的频率更高,但这也很多easier手动进行类型转换而不是翻转。如果您曾经在 Python 中完成过此操作,请选择操作数%
正确地识别标志当然很容易出错;投射到BigInt
很难搞砸。
最后,在强类型语言(如 Python 和 Julia)中,类型稳定性很重要。 Python 3 存在的原因之一是旧的str
类型神奇地转换为unicode
造成了问题。这对你来说不太常见int
类型神奇地转换为long
会导致问题,但这种情况也有可能发生(例如,当您从网络上或通过 C API 获取一个值,并期望以相同的格式写出结果时)。 Python的开发团队在做的时候就这个问题争论过int
/long
统一,引用“实用胜于纯粹”和禅宗的其他一些内容,并最终决定旧行为比新行为造成更多问题。朱莉娅的设计做出了相反的决定。