在尝试解决Julia中的Project Euler问题时,我遇到了一个小问题。我基本上写了一个递归函数,它产生具有越来越大的分子和分母的分数。我不想出于显而易见的原因发布代码,但最后几个部分如下:
1180872205318713601//835002744095575440
2850877693509864481//2015874949414289041
6882627592338442563//4866752642924153522
此时我得到一个OverflowError()
,大概是因为分子和/或分母现在超过了19位数。有办法处理' Big' Julia中的分数(即具有BigInt型分子和分母的分数)?
附录:
好的,我已经简化了代码并伪装了一下。如果有人想通过650项计划欧拉问题来试图弄清楚它是哪个问题,祝他们好运 - 可能会有大约200个更好的解决方案!
function series(limit::Int64, i::Int64=1, n::Rational{Int64}=1//1)
while i <= limit
n = 1 + 1//(1 + 2n)
println(n)
return series(limit, i + 1, n)
end
end
series(50)
如果我运行上面的函数,比方说20作为参数运行正常。有了50,我得到了OverflowError()
。
答案 0 :(得分:4)
Julia默认使用机器整数。有关详细信息,请参阅常见问题解答:Why does Julia use native machine integer arithmetic?。
简而言之:任何现代CPU上最有效的整数运算都涉及在固定位数上进行计算。在你的机器上,这是64位。
julia> 9223372036854775805 + 1
9223372036854775806
julia> 9223372036854775805 + 2
9223372036854775807
julia> 9223372036854775805 + 3
-9223372036854775808
哇!刚刚发生了什么!?这绝对是错的!如果你看看这些数字是如何用二进制表示的,那就更明显了:
julia> bitstring(9223372036854775805 + 1)
"0111111111111111111111111111111111111111111111111111111111111110"
julia> bitstring(9223372036854775805 + 2)
"0111111111111111111111111111111111111111111111111111111111111111"
julia> bitstring(9223372036854775805 + 3)
"1000000000000000000000000000000000000000000000000000000000000000"
所以你可以看到那些63位&#34;用完空间&#34;并翻过来 - 第64位称为&#34;符号位&#34;并发出一个负数。
当您看到这样的溢出时,有两种可能的解决方案:您可以使用&#34;检查算术&#34; - 就像理性代码那样 - 确保你不会无声地解决这个问题:
julia> Base.Checked.checked_add(9223372036854775805, 3)
ERROR: OverflowError: 9223372036854775805 + 3 overflowed for type Int64
或者您可以使用更大的整数类型 - 例如无界BigInt
:
julia> big(9223372036854775805) + 3
9223372036854775808
因此,一个简单的解决方法是删除类型注释并根据limit
动态选择整数类型:
function series(limit, i=one(limit), n=one(limit)//one(limit))
while i <= limit
n = 1 + 1//(1 + 2n)
println(n)
return series(limit, i + 1, n)
end
end
julia> series(big(50))
#…
1186364911176312505629042874//926285732032534439103474303
4225301286417693889465034354//3299015554385159450361560051