perl6:无法将 65536 位宽的 bigint 拆箱为本机整数
perl6: Cannot unbox 65536 bit wide bigint into native integer
我尝试了 Rosettacode 中的一些示例,并遇到了提供的 Ackermann 示例的问题:当 运行 它 "unmodified" (我用 latin-1 替换了 utf-8 变量名一个),我得到(类似,但现在可复制):
$ perl6 t/ackermann.p6
65533
19729 digits starting with 20035299304068464649790723515602557504478254755697...
Cannot unbox 65536 bit wide bigint into native integer
in sub A at t/ackermann.p6 line 3
in sub A at t/ackermann.p6 line 11
in sub A at t/ackermann.p6 line 3
in block <unit> at t/ackermann.p6 line 17
删除第 3 行中的 proto 声明(通过注释掉):
$ perl6 t/ackermann.p6
65533
19729 digits starting with 20035299304068464649790723515602557504478254755697...
Numeric overflow
in sub A at t/ackermann.p6 line 8
in sub A at t/ackermann.p6 line 11
in block <unit> at t/ackermann.p6 line 17
出了什么问题?该程序没有分配太多内存。自然整数是有限制的吗?
我在 Ackermann function 的代码中替换了 with m 和 with n 以获得更好的终端交互以复制错误,并尝试注释掉 proto 声明。我也问过Liz ;)
use v6;
proto A(Int \m, Int \n) { (state @)[m][n] //= {*} }
multi A(0, Int \n) { n + 1 }
multi A(1, Int \n) { n + 2 }
multi A(2, Int \n) { 3 + 2 * n }
multi A(3, Int \n) { 5 + 8 * (2 ** n - 1) }
multi A(Int \m, 0 ) { A(m - 1, 1) }
multi A(Int \m, Int \n) { A(m - 1, A(m, n - 1)) }
# Testing:
say A(4,1);
say .chars, " digits starting with ", .substr(0,50), "..." given A(4,2);
A(4, 3).say;
数组下标使用native ints;这就是当您使用大整数作为数组下标时在第 3 行出现错误的原因。您可能必须定义一个使用 Int 作为数组下标的新 BigArray。
第二个问题出现在**运算符中:结果是一个Real,当低级运算returns一个Num时,会抛出异常。
https://github.com/rakudo/rakudo/blob/master/src/core/Int.pm6#L391-L401
因此创建 BigArray 可能无论如何都没有帮助。你也必须创建你自己的 **,它总是与 Int 一起工作,但你似乎已经达到了无限精度 Ints 的(不是那么无限)限制。
请先阅读JJ的回答。它很轻松,并导致了这个答案,实际上是对它的详细阐述。
TL;DR A(4,3)
是一个非常的大数,在这个宇宙中无法计算。但是 raku(do) 会尝试。如果您使用缓存版本,那么您将突破与内存分配和索引相关的合理限制,如果您不使用,则将突破与数值计算相关的限制。
I try some examples from Rosettacode and encounter an issue with the provided Ackermann example
引用任务描述并强调:
Arbitrary precision is preferred (since the function grows so quickly)
raku 的标准整数类型 Int
是 arbitrary precision。 raku 解决方案使用它们来计算可能的最高级答案。只有当你让它尝试做不可能的事情时它才会失败。
When running it "unmodified" (I replaced the utf-8 variable names by latin-1 ones)
替换变量名并不是一个重大变化。
但是添加 A(4,3)
行将代码从现实中的可计算状态转变为现实中的不可计算状态。
您修改的示例只有一条解释性注释:
Here's a caching version of that ... to make A(4,2) possible
请注意,A(4,2)
解决方案的长度接近 20,000 位。
如果您查看该页面上的其他解决方案,大多数甚至不会尝试达到 A(4,2)
。 Phix版有这样的评论:
optimised. still no bignum library, so ack(4,2), which is power(2,65536)-3, which is apparently 19729 digits, and any above, are beyond (the CPU/FPU hardware) and this [code].
A(4,2)
的解决方案是最先进的。
A(4,3)
在实践中不可计算
引用Academic Kids: Ackermann function:
Even for small inputs (4,3, say) the values of the Ackermann function become so large that they cannot be feasibly computed, and in fact their decimal expansions cannot even be stored in the entire physical universe.
所以计算 A(4,3).say
是不可能的(在这个宇宙中)。
它必然会导致甚至任意精度整数运算的溢出。这只是时间和方式的问题。
Cannot unbox 65536 bit wide bigint into native integer
第一条错误消息提到了这行代码:
proto A(Int \m, Int \n) { (state @)[m][n] //= {*} }
state @
是一个 anonymous state array variable。
默认 @
个变量使用 the default concrete type for raku's abstract array type。此默认数组类型在实现复杂性和良好性能之间提供了平衡。
在计算 A(4,2)
时,索引(m
和 n
)保持足够小,以便计算完成而不会溢出默认数组的索引限制。
此限制是一个“本机”整数(注意:不是 "natural" integer). A "native" integer is what raku calls the fixed width integers supported by the hardware it's running on, typically a long long 通常是 64 位。
64 位宽的索引最多可以处理 9,223,372,036,854,775,807。
但是在尝试计算 A(4,3)
时,该算法会生成一个 65536 位(8192 字节)宽的整数索引。这样的整数可能大到265536,一个20,032 decimal digit number。但允许的最大索引是 64 位本机整数。因此,除非您注释掉使用数组的缓存行,否则对于 A(4,3)
程序最终会抛出异常:
Cannot unbox 65536 bit wide bigint into native integer
默认数组类型的分配和索引限制
如前所述,没有大到足以帮助完全计算 A(4,3)
的数组。此外,64位整数已经是一个相当大的索引(9,223,372,036,854,775,807
)。
就是说,raku 可以容纳其他数组实现,例如 Array::Sparse
所以我将在下面简要讨论,因为其他问题可能会对这种可能性感兴趣。
但在讨论更大的数组之前,running the code below on tio.run 显示了该平台上默认数组类型的实际限制:
my @array;
@array[2**29]++; # works
@array[2**30]++; # could not allocate 8589967360 bytes
@array[2**60]++; # Unable to allocate ... 1152921504606846977 elements
@array[2**63]++; # Cannot unbox 64 bit wide bigint into native integer
(注释掉错误行以查看 later/greater 个错误。)
“无法分配 8589967360 字节”错误是 MoarVM 恐慌。这是 tio.run 拒绝内存分配请求的结果。
我认为“无法分配...元素”错误是 raku 级别的异常,是由于超出某些内部 Rakudo 实现限制而引发的。
最后一条错误消息显示了默认数组类型的索引限制,即使程序可以使用大量内存也是如此。
如果有人想做更大的索引怎么办?
可以 create/use 其他 @
(does Positional
) 支持稀疏数组等的数据类型
并且,使用这种机制,有人可以编写支持比默认数组类型支持的更大的整数索引的数组实现(大概是通过在底层平台指令之上分层逻辑;也许 Array::Sparse
我在上面链接了)。
如果这样的替代方法被称为 BigArray
那么缓存行可以替换为:
my @array is BigArray;
proto A(Int \, Int \) { @array[][] //= {*} }
同样,这个 仍然 不足以存储完全计算的临时结果 A(4,3)
但我的意思是展示自定义数组类型的使用。
Numeric overflow
当您注释掉缓存时,您会得到:
Numeric overflow
Raku/Rakudo 做任意精度运算。虽然这有时被称为无限精度,但它显然不是 实际上 无限,而是“任意”,在这种情况下,对于“理智”的某些定义也意味着“理智” .
这通常意味着 运行 内存不足,无法存储数字。但在 Rakudo 的情况下,我认为有人试图通过在完全 运行 超出 RAM 之前从真正巨大的 Int
切换到 Num
(浮点数)来保持理智。但是随后计算 A(4,3)
最终甚至会溢出双浮点数。
因此,虽然缓存会更快地崩溃,但代码肯定会在稍后崩溃,然后你会得到一个数字溢出,它要么表现为内存不足错误,要么表现为数字溢出错误。在这种情况下。
我尝试了 Rosettacode 中的一些示例,并遇到了提供的 Ackermann 示例的问题:当 运行 它 "unmodified" (我用 latin-1 替换了 utf-8 变量名一个),我得到(类似,但现在可复制):
$ perl6 t/ackermann.p6
65533
19729 digits starting with 20035299304068464649790723515602557504478254755697...
Cannot unbox 65536 bit wide bigint into native integer
in sub A at t/ackermann.p6 line 3
in sub A at t/ackermann.p6 line 11
in sub A at t/ackermann.p6 line 3
in block <unit> at t/ackermann.p6 line 17
删除第 3 行中的 proto 声明(通过注释掉):
$ perl6 t/ackermann.p6
65533
19729 digits starting with 20035299304068464649790723515602557504478254755697...
Numeric overflow
in sub A at t/ackermann.p6 line 8
in sub A at t/ackermann.p6 line 11
in block <unit> at t/ackermann.p6 line 17
出了什么问题?该程序没有分配太多内存。自然整数是有限制的吗?
我在 Ackermann function 的代码中替换了 with m 和 with n 以获得更好的终端交互以复制错误,并尝试注释掉 proto 声明。我也问过Liz ;)
use v6;
proto A(Int \m, Int \n) { (state @)[m][n] //= {*} }
multi A(0, Int \n) { n + 1 }
multi A(1, Int \n) { n + 2 }
multi A(2, Int \n) { 3 + 2 * n }
multi A(3, Int \n) { 5 + 8 * (2 ** n - 1) }
multi A(Int \m, 0 ) { A(m - 1, 1) }
multi A(Int \m, Int \n) { A(m - 1, A(m, n - 1)) }
# Testing:
say A(4,1);
say .chars, " digits starting with ", .substr(0,50), "..." given A(4,2);
A(4, 3).say;
数组下标使用native ints;这就是当您使用大整数作为数组下标时在第 3 行出现错误的原因。您可能必须定义一个使用 Int 作为数组下标的新 BigArray。
第二个问题出现在**运算符中:结果是一个Real,当低级运算returns一个Num时,会抛出异常。 https://github.com/rakudo/rakudo/blob/master/src/core/Int.pm6#L391-L401
因此创建 BigArray 可能无论如何都没有帮助。你也必须创建你自己的 **,它总是与 Int 一起工作,但你似乎已经达到了无限精度 Ints 的(不是那么无限)限制。
请先阅读JJ的回答。它很轻松,并导致了这个答案,实际上是对它的详细阐述。
TL;DR A(4,3)
是一个非常的大数,在这个宇宙中无法计算。但是 raku(do) 会尝试。如果您使用缓存版本,那么您将突破与内存分配和索引相关的合理限制,如果您不使用,则将突破与数值计算相关的限制。
I try some examples from Rosettacode and encounter an issue with the provided Ackermann example
引用任务描述并强调:
Arbitrary precision is preferred (since the function grows so quickly)
raku 的标准整数类型 Int
是 arbitrary precision。 raku 解决方案使用它们来计算可能的最高级答案。只有当你让它尝试做不可能的事情时它才会失败。
When running it "unmodified" (I replaced the utf-8 variable names by latin-1 ones)
替换变量名并不是一个重大变化。
但是添加 A(4,3)
行将代码从现实中的可计算状态转变为现实中的不可计算状态。
您修改的示例只有一条解释性注释:
Here's a caching version of that ... to make A(4,2) possible
请注意,A(4,2)
解决方案的长度接近 20,000 位。
如果您查看该页面上的其他解决方案,大多数甚至不会尝试达到 A(4,2)
。 Phix版有这样的评论:
optimised. still no bignum library, so ack(4,2), which is power(2,65536)-3, which is apparently 19729 digits, and any above, are beyond (the CPU/FPU hardware) and this [code].
A(4,2)
的解决方案是最先进的。
A(4,3)
在实践中不可计算
引用Academic Kids: Ackermann function:
Even for small inputs (4,3, say) the values of the Ackermann function become so large that they cannot be feasibly computed, and in fact their decimal expansions cannot even be stored in the entire physical universe.
所以计算 A(4,3).say
是不可能的(在这个宇宙中)。
它必然会导致甚至任意精度整数运算的溢出。这只是时间和方式的问题。
Cannot unbox 65536 bit wide bigint into native integer
第一条错误消息提到了这行代码:
proto A(Int \m, Int \n) { (state @)[m][n] //= {*} }
state @
是一个 anonymous state array variable。
默认 @
个变量使用 the default concrete type for raku's abstract array type。此默认数组类型在实现复杂性和良好性能之间提供了平衡。
在计算 A(4,2)
时,索引(m
和 n
)保持足够小,以便计算完成而不会溢出默认数组的索引限制。
此限制是一个“本机”整数(注意:不是 "natural" integer). A "native" integer is what raku calls the fixed width integers supported by the hardware it's running on, typically a long long 通常是 64 位。
64 位宽的索引最多可以处理 9,223,372,036,854,775,807。
但是在尝试计算 A(4,3)
时,该算法会生成一个 65536 位(8192 字节)宽的整数索引。这样的整数可能大到265536,一个20,032 decimal digit number。但允许的最大索引是 64 位本机整数。因此,除非您注释掉使用数组的缓存行,否则对于 A(4,3)
程序最终会抛出异常:
Cannot unbox 65536 bit wide bigint into native integer
默认数组类型的分配和索引限制
如前所述,没有大到足以帮助完全计算 A(4,3)
的数组。此外,64位整数已经是一个相当大的索引(9,223,372,036,854,775,807
)。
就是说,raku 可以容纳其他数组实现,例如 Array::Sparse
所以我将在下面简要讨论,因为其他问题可能会对这种可能性感兴趣。
但在讨论更大的数组之前,running the code below on tio.run 显示了该平台上默认数组类型的实际限制:
my @array;
@array[2**29]++; # works
@array[2**30]++; # could not allocate 8589967360 bytes
@array[2**60]++; # Unable to allocate ... 1152921504606846977 elements
@array[2**63]++; # Cannot unbox 64 bit wide bigint into native integer
(注释掉错误行以查看 later/greater 个错误。)
“无法分配 8589967360 字节”错误是 MoarVM 恐慌。这是 tio.run 拒绝内存分配请求的结果。
我认为“无法分配...元素”错误是 raku 级别的异常,是由于超出某些内部 Rakudo 实现限制而引发的。
最后一条错误消息显示了默认数组类型的索引限制,即使程序可以使用大量内存也是如此。
如果有人想做更大的索引怎么办?
可以 create/use 其他 @
(does Positional
) 支持稀疏数组等的数据类型
并且,使用这种机制,有人可以编写支持比默认数组类型支持的更大的整数索引的数组实现(大概是通过在底层平台指令之上分层逻辑;也许 Array::Sparse
我在上面链接了)。
如果这样的替代方法被称为 BigArray
那么缓存行可以替换为:
my @array is BigArray;
proto A(Int \, Int \) { @array[][] //= {*} }
同样,这个 仍然 不足以存储完全计算的临时结果 A(4,3)
但我的意思是展示自定义数组类型的使用。
Numeric overflow
当您注释掉缓存时,您会得到:
Numeric overflow
Raku/Rakudo 做任意精度运算。虽然这有时被称为无限精度,但它显然不是 实际上 无限,而是“任意”,在这种情况下,对于“理智”的某些定义也意味着“理智” .
这通常意味着 运行 内存不足,无法存储数字。但在 Rakudo 的情况下,我认为有人试图通过在完全 运行 超出 RAM 之前从真正巨大的 Int
切换到 Num
(浮点数)来保持理智。但是随后计算 A(4,3)
最终甚至会溢出双浮点数。
因此,虽然缓存会更快地崩溃,但代码肯定会在稍后崩溃,然后你会得到一个数字溢出,它要么表现为内存不足错误,要么表现为数字溢出错误。在这种情况下。