let n = read_int();;
let ftp = Hashtbl.create 1;;
let rec perrin n =
match n with
0 -> 3
|1 -> 0
|2 -> 2
|_ -> if Hashtbl.mem ftp n
then Hashtbl.find ftp n
else
begin
Hashtbl.add ftp n (perrin (n-2) + perrin (n-3));
Hashtbl.find ftp n
end;;
print_int (perrin n);;
print_newline ();;
该功能适用于小数字。但是对于大数字开始在结果中返回负数。有谁知道如何解决这个问题? 例如:
perrin 6443;;
输出:返回意外结果
答案 0 :(得分:3)
简而言之,这是因为整数溢出。 perrin编号6443非常大,不适合标准的OCaml表示。您可以切换到int64类型,但很快就会达到最大值。如果您想计算任意长度的perrin数,那么您应该切换到一些提供任意大数字的库,例如Zarith。
以下是相同算法的示例,它使用任意精度数计算perrin数(使用Zarith库):
let ftp = Hashtbl.create 1
let (+) = Z.add
let rec perrin n =
match n with
| 0 -> Z.of_int 3
| 1 -> Z.of_int 0
| 2 -> Z.of_int 2
|_ -> if Hashtbl.mem ftp n
then Hashtbl.find ftp n
else
begin
Hashtbl.add ftp n (perrin (n-2) + perrin (n-3));
Hashtbl.find ftp n
end
以下是结果:
# #install_printer Z.pp_print;;
# perrin 6443;;
- : Z.t =
6937727487481534145345362428447384488478299624972546803624695551910667531554047522814387413304226129434527926499509496229770899828053746244703038130158033495659756925642507460705324476565619563726313143585381473818236243926914534542432440183345586679670347146768666345957457035004600496858722149019370892348066080092386227405747647480490430105430719428536606680584617305233160609609912020683184996768739606851007812320606992975981778299643926692143069608878875765580902743031572791438636355138605019665803104979890697923714757674707178907100143056837109943637042907642787339851137110850937972239227931113199614637067827389939915715964263895232644082473556841869600234790536494644702234455771939854947229042244627157330814752633389708917381476591438570001576028511405244641287078061574227
#
您可能会注意到这个数字确实很大,并且没有机会适应32位甚至64位。实际上,它需要2614位:
# Z.numbits (perrin 6443);;
- : int = 2614
如果您不想安装zarith
库并添加额外的依赖项,那么您可以使用OCaml builtin Big_int
模块获取任意精度数字。以下是基于Big_int
模块的实现:
open Big_int
let ftp = Hashtbl.create 1
let (+) = add_big_int
let rec perrin n =
match n with
| 0 -> big_int_of_int 3
| 1 -> big_int_of_int 0
| 2 -> big_int_of_int 2
|_ -> if Hashtbl.mem ftp n
then Hashtbl.find ftp n
else
begin
Hashtbl.add ftp n (perrin (n-2) + perrin (n-3));
Hashtbl.find ftp n
end;;