理解BigInt的使用

9
我很难理解如何正确使用BigInt。在我看来,当Int64或Int128不足时,应该使用BigInt,显然BigInt使用任意精度算术(我对此一无所知)。
比如说我想计算一个很大的数字的阶乘,比如30。我不知道存储factorial(30)需要多少位,但是两者都可以使用BigInt和普通整数类型进行计算。
test = Int128
test = factorial(30)

并且

test = BigInt
test = factorial(30)

生成的结果为-8764578968847253504,显然是错误的。

根据Julia lang文档,似乎这种类型(BigInt)定义了常规的数学运算符,并将结果提升为BigInt。因此我无法看出我做错了什么,显然我误解了一些东西。希望你们中的一些人可以为我解释一下 :)

附:我正在运行64位的Windows 7,如果有任何影响,请告诉我。

3个回答

16

factorial函数将返回与其参数相同类型的结果。

test = factorial(BigInt(30))  

会起作用,将在整个计算过程中使用BigInt

test = BigInt(factorial(30))

不起作用,会将已经溢出的 Int 结果转换为 BigInt。

test = BigInt(factorial(BigInt(30)))

这样做虽然可以工作,但外部的 BigInt 是多余的,因为结果已经是一个 BigInt。

你编写的代码

test = BigInt
test = factorial(30)

本质上是没有意义的。你说:

  

根据Julia编程语言的文档,似乎这种类型(BigInt)已定义了通常的数学运算符,并且结果会提升为BigInt。

所以我猜你认为这意味着“结果应该是一个BigInt”,但它并不是这样。它将类型BigInt分配给变量test,然后计算Int文字30的factorial。然后将其存储在test中,压制先前的值,即BigInt。也许你应该查看手册中的类型部分。Julia不会自动将Ints提升为BigInts以处理溢出-您需要从BigInt开始。这是为了性能(和其他)原因。

大多数操作都定义在BigInt上 - 只有一些线性代数操作(例如特征值)可能不支持。只需将您的数字更改为BigInt,它将传播到整个计算中。大多数人永远不需要BigInt - 它们只会在研究环境中出现。 Int(与平台整数大小相同,因此在计算机上为Int64)可以很大并且很快。


1
谢谢解释,很有道理。从现在开始处理 BigInts 时会坚持使用显式转换 :) - kip820

2

关于任意精度数学的相关问题。注意,我只花了两天时间尝试使用Julia语言。在查看了这个帖子之后,我添加了BigInt转换,这样就可以多打印一个数字了。但是我肯定漏掉了什么,因为它仍然不能像需要的那样执行所有计算的任意精度。我还必须添加try/catch,因为ismersenneprime函数会在不是Mersenne质数时抛出错误。根据文档,我以为它应该返回true或false。

# Perfect numbers are 2^(p-1)x(2^p-1) if 2^p-1 is Mersenne prime.
using Compat
using Primes

limit = 1000000

for p = 1:limit
  perfect = BigInt(2^(p-1))*(BigInt(2^p)-1)
  try 
    if ismersenneprime(BigInt(2^p)-1)
      println("$p $perfect")
    end
  catch e
#   println(e)
  end
end

2 6
3 28
5 496
7 8128
13 33550336
17 8589869056
19 137438691328
31 2305843008139952128
61 2658455991569831744654692615953842176

我想我也没有掌握在这里发布的技巧,因为它完全破坏了格式。未来是否可以只使用HTML标记,例如<pre> </pre>? - user3316586
我最终通过重新定义limit为limit = BigInt(typemax(Int128)) + 1使其正常工作。 - user3316586

2
我想在回答之前声明,我对Julia一无所知,但是阅读https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/#Arbitrary-Precision-Arithmetic-1上的文档可以看到他们使用了factorial(BigInt(40)),因此明确的转换似乎是必需的。
尝试factorial(BigInt(30))看看是否能得到预期结果。
此外,从那个页面上可以看到:

然而,在原始类型和BigInt/BigFloat之间进行类型提升并不自动进行,必须明确说明。

因此,我会尝试三件事情,看看哪一个有效。
test = factorial(BigInt(30))
test = BigInt(factorial(30))
test = BigInt(factorial(BigInt(30)))

1
谢谢,这个方法可行。这其实很有道理,因为Julia中的大多数函数都是多态的(我想我在这里使用了多态的正确术语),所以当factorial获取一个BigInt类型时,它也会返回一个BigInt类型,与我最初做的相反,那时我给它提供了一个Int类型。 - kip820
澄清一下,显式转换起作用了,你列表中的第一个例子完美地运行了,其他的我还没有尝试过。 - kip820
1
需要注意的是,在Julia中,如果我理解正确的话,BigInt(30)不是强制转换,也不是转换或提升(尽管这些操作在Julia中是可能的)。实际上,您正在调用一个构造函数。手册详细解释了这一点以及更多细节。 - rickhg12hs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接