我在Python中定义了一个阶乘函数如下:
def fact(n):
if n == 1:
return n
else:
return n * fact(n-1)
print(fact(100))
Run Code Online (Sandbox Code Playgroud)
如下朱莉娅:
function fact(n)
if n == 1
n
else
n * fact(n-1)
end
end
println(fact(100))
Run Code Online (Sandbox Code Playgroud)
python程序返回一个非常大的数字,用于评估100(如预期的那样).Julia返回0.使用较小的数字(如10)它们都可以工作.
我有两个问题:
aba*_*ert 20
Julia有单独的固定大小整数类型,加上BigInt类型.默认类型是Int64,当然是64位.
100以来!需要大约526位,它显然溢出了一个Int64.
你可以通过这样做来解决这个问题fact(BigInt(100))(假设你已经这样做require了),或者当然你可以在fact函数中进行转换.
从前,Python曾经是相同的.它有不同的类型int,根据你的机器有16或32或64位,并且long是任意长度的.如果您在Python 1.5上运行程序,它将像Julia一样包裹,或者引发异常.解决方案是调用fact(100L)或转换到函数long内部fact.
但是,在2.x系列中的某些时候,Python将这两种类型绑定在一起,因此任何int溢出都会自动变为a long.然后,在3.0中,它完全合并了两种类型,因此long不再有单独的.
那么,为什么朱莉娅只是溢出而不是提出错误?
FAQ实际上解释了为什么Julia使用本机整数算术.其中包括溢出时的环绕行为.
通过"原生机器算术",人们通常意味着"C几乎在所有2s补充机器上做什么".特别是在像Julia和Python这样的语言中,它们最初构建在C语言之上,并且非常接近金属.就朱莉娅而言,这不仅仅是一种"默认",而是一种有意的选择.
在C中(至少和当时一样),它实际上取决于实现如果你溢出一个有符号整数类型的情况会发生什么int64......但是在几乎任何本地使用2的补码算法的平台上(几乎任何平台你都会看到今天),完全相同的事情发生:它只是截断前64位以上的所有内容,这意味着你从正面到负面回绕.实际上,无符号整数类型需要在C中以这种方式工作.(同时,C也是这样工作的,因为这是大多数CPU的工作方式.)
在C语言中(与大多数CPU的机器语言不同),没有办法检测到事后你已经溢出了.因此,如果你想提高一个OverflowError,你必须编写一些逻辑来检测乘法在执行之前会溢出.而且你必须在每一次乘法运行逻辑.您可以通过编写内联汇编代码为某些平台优化此功能.或者你可以转换为更大的类型,但(a)往往会使你的代码变慢,(b)如果你已经使用了最大的类型(int64今天在很多平台上),它就不起作用了.
在Python中,使每个乘法速度降低4倍(通常更少,但可能会更高)并不是什么大问题,因为Python花费更多时间获取字节码并取消整理对象而不是乘法.但朱莉娅意味着比这更快.
正如John Myles White在" 计算机是机器"中所解释的:
在许多方面,朱莉娅通过尝试恢复从C语言转换为Python等语言时失去的一些力量,使自己与其他新语言区分开来.但转型带来了实质性的学习曲线.
但是还有另一个原因:在很多情况下,溢出的带符号算法实际上很有用.几乎没有溢出无符号算术那么多(这就是为什么C在第一个ANSI规范之前定义了无符号算术以此方式工作的原因),但是有一些用例.
而且,即使你可能比想要翻转更频繁地想要类型转换,手动进行类型转换要比翻转更容易.如果你曾经用Python做过,那么选择操作数%并获得正确的符号肯定容易出错; 铸造BigInt很难搞砸.
最后,在强类型语言中,如Python和Julia,类型稳定性很重要.Python 3存在的原因之一是旧str类型神奇地转换为unicode导致问题.你的int类型神奇地转换为long导致问题的类型远不常见,但它可能发生(例如,当你从线上获取值,或通过C API,并期望以相同的格式写出结果) .Python的开发团队在做int/ long统一时引用了这一点,引用了"实用性超越纯度"和禅的其他各种内容,并最终决定旧行为导致的问题多于新行为.朱莉娅的设计做出了相反的决定.
iva*_*rne 17
没有人回答为什么朱莉娅的结果是0.
Julia不检查溢出的整数乘法,因此64位整数的乘法执行mod 2 ^ 63.请参阅此FAQ条目
当你写出你得到的阶乘的乘法时
1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20*21*22*23*24*25*26*27*28*29*30*31*32*33*34*35*36*37*38*39*40*41*42*43*44*45*46*47*48*49*50*51*52*53*54*55*56*57*58*59*60*61*62*63*64*65*66*67*68*69*70*71*72*73*74*75*76*77*78*79*80*81*82*83*84*85*86*87*88*89*90*91*92*93*94*95*96*97*98*99*100
Run Code Online (Sandbox Code Playgroud)
这也可以写为主要因素
2^97 * 3^48 * 5^24 * 7^16 * 11^9 * 13^7 * 17^5 * 19^5 * 23^4 * 29^3 * 31^3 * 37^2 * 41^2 * 43^2 * 47^2 * 53^1 * 59^1 * 61^1 * 67^1 * 71^1 * 73^1 * 79^1 * 83^1 * 89^1 * 97^1
Run Code Online (Sandbox Code Playgroud)
如果你看看2你得到的指数97.模块化算术使您可以在计算的任何步骤执行mod函数,并且不会影响结果.2^97 mod 2^63 == 0与链的其余部分相乘的也是0.
更新: 我当然懒得在纸上做这个计算.
d = Dict{Int,Int}()
for i=1:100
for (k,v) in factor(i)
d[k] = get(d,k,0) + v
end
end
for k in sort(collect(keys(d)))
print("$k^$(d[k])*")
end
Run Code Online (Sandbox Code Playgroud)
Julia在其标准库中有一个非常方便的factor()函数.
Jam*_*lls 10
我想这个答案是使用BigInt:
function fact(n::BigInt)
if n == BigInt(1)
n
else
n * fact(n-BigInt(1))
end
end
println(fact(BigInt(100)))
Run Code Online (Sandbox Code Playgroud)
结果如下:
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Run Code Online (Sandbox Code Playgroud)
测试:http://forio.com/julia/repl/
正如其他一些答案中所述,Python会隐式地将超过最大大小的int(s)转换为bigint(s),因此您可以获得预期的结果而不是静默失败.
另一方面,朱莉娅似乎对此更加明确,并倾向于表现而非"预期行为".Julia是一种带有OPtional Type Annotations和Inference的动态语言.