Int64在递归函数中的使用

huangapple go评论68阅读模式
英文:

Int64 usage in recursive functions

问题

以下是要翻译的代码部分:

let rec f n:int64=
 if n<1 then 1L
 else (4*n-2)*f((n-1L))/(n+1L)
;;
for i = 0 to 50 do
  Printf.printf "%d\n"(f i)
done;

但问题是,递归函数似乎不接受Int64值,似乎希望使用Int而不是,尽管我将n标记为int64

File "/proc/self/fd/0", line 3, characters 19-21:
3 |  else (4*n-2)*f((n-1L))/(n+1L)
                       ^^
Error: This expression has type int64 but an expression was expected of type
         int
exit status 2

是否有一种方法可以确保我在递归中使用int64数字?

英文:

I have the following code written in Ocaml to try and generate the first 50 catalan numbers:

let rec f n:int64=
 if n&lt;1 then 1L
 else (4*n-2)*f((n-1L))/(n+1L)
;;
for i = 0 to 50 do
  Printf.printf &quot;%d\n&quot;(f i)
done;

But the problem is that the recursion function doesn't seem to accept Int64 values and seems to want Int instead despite me notating n as int64:

File &quot;/proc/self/fd/0&quot;, line 3, characters 19-21:
3 |  else (4*n-2)*f((n-1L))/(n+1L)
                       ^^
Error: This expression has type int64 but an expression was expected of type
         int
exit status 2

Is there a way to ensure I can int64 numbers here with recursion?

答案1

得分: 2

你的问题并不是递归本身,而是OCaml中的运算符具有强类型。所以-运算符的类型是int -> int -> int

不需要过多纠结于语法,最简单的修复方法可能是使用Int64模块的命名函数。例如,你可以使用Int64.sub而不是-

你可以使用表示法Int64.(... <expr> ...)来避免重复模块名称。如果你按照这种方式重写你的代码,会得到如下结果:

let rec f (n : int64) : int64 =
    Int64.(
        if n < 1L then 1L
        else
            mul (sub (mul 4L n) 2L)
                (f (div (sub n 1L) (add n 1L)))
    )

查看这个函数计算的结果,它们看起来并不像卡塔兰数。事实上,第50个卡塔兰数太大,无法表示为int64值。
所以还有一些工作要做。但这是克服你遇到的问题的方法(依我之见)。

如果你真的想要处理如此大的数字,你可能需要查看Zarith模块

英文:

Your problem isn't recursion per se, it's that the operators in OCaml are strongly typed. So the - operator is of type int -&gt; int -&gt; int.

Without getting into lots of fussing with the syntax, the easiest fix is probably to use the named functions of the Int64 module. You can use Int64.sub rather than -, for example.

You can use the notation Int64.(... &lt;expr&gt; ...) to avoid repeating the module name. If you rewrite your code this way, you get something like this:

let rec f (n : int64) : int64 =
    Int64.(
        if n &lt; 1L then 1L
        else
            mul (sub (mul 4L n) 2L)
                (f (div (sub n 1L) (add n 1L)))
    )

Looking at the results computed by this function, they don't look like Catalan numbers to me. In fact the 50th Catalan number is too large to be represented as an int64 value.
So there is still some work to do. But this is how to get past the problem you're seeing (IMHO).

If you really want to work with such large numbers, you probably want to look at the Zarith module.

答案2

得分: 1

作为对Jeffrey答案的额外建议提交:无论是使用Int64还是Zarith,您可以创建一个定义算术运算符的模块,然后在本地打开该模块以简化您的代码。

例如:

module Int64Ops =
struct
  let ( + ) = Int64.add
  let ( - ) = Int64.sub
  let ( * ) = Int64.mul
  let ( / ) = Int64.div
end

let rec f n =
  Int64Ops.(
    if n < 1L then 1L
    else (4L * n - 2L) * f (n - 1L) / (n + 1L)
  )

或者您可以使用一个functor,以便更轻松地处理多种不同类型的数字。

module type S =
sig
  type t
  val add : t -> t -> t
  val sub : t -> t -> t
  val mul : t -> t -> t
  val div : t -> t -> t
end

module BasicArithmeticOps (X : S) = 
struct
  type t = X.t
  let ( + ) = X.add
  let ( - ) = X.sub
  let ( * ) = X.mul
  let ( / ) = X.div
end
# let module A = BasicArithmeticOps (Float) in
A.(8. + 5.1);;
- : float = 13.1
# let module A = BasicArithmeticOps (Int) in
A.(8 + 3);;
- : int = 11
# let module A = BasicArithmeticOps (Int64) in
A.(4L + 3L);;
- : int64 = 7L
英文:

Submitted as an additional suggestion to Jeffrey's answer: whether using Int64 or Zarith, you might create a module defining arithmetic operators and then locally open that to clean up your code.

E.g.

module Int64Ops =
struct
  let ( + ) = Int64.add
  let ( - ) = Int64.sub
  let ( * ) = Int64.mul
  let ( / ) = Int64.div
end

let rec f n =
  Int64Ops.(
    if n &lt; 1L then 1L
    else (4L * n - 2L) * f (n - 1L) / (n + 1L)
  )

Or you could use a functor to make it easier to work with multiple different types of numbers.

module type S =
sig
  type t
  val add : t -&gt; t -&gt; t
  val sub : t -&gt; t -&gt; t
  val mul : t -&gt; t -&gt; t
  val div : t -&gt; t -&gt; t
end

module BasicArithmeticOps (X : S) = 
struct
  type t = X.t
  let ( + ) = X.add
  let ( - ) = X.sub
  let ( * ) = X.mul
  let ( / ) = X.div
end
# let module A = BasicArithmeticOps (Float) in
A.(8. + 5.1);;
- : float = 13.1
# let module A = BasicArithmeticOps (Int) in
A.(8 + 3);;
- : int = 11
# let module A = BasicArithmeticOps (Int64) in
A.(4L + 3L);;
- : int64 = 7L

huangapple
  • 本文由 发表于 2023年1月6日 14:52:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75027829.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定