用OCaml计算欧拉常数
Calculating Euler's constant with OCaml
我今天开始学习OCaml。我已经知道 Scheme,所以我认为尝试将一些示例 Scheme 程序转换为 ML 会很好。我在下面有一些代码用于计算有效的欧拉数,但它在 OCaml 中不起作用。我得到这个错误:Exception: Division_by_zero.
我认为这可能是在某处混合浮点数和整数的问题。我无法弄清楚如何使用 ocamldebug
为函数设置断点。任何人都可以确定我的错误发生在哪里吗?谢谢。
(define (factorial n)
(if (zero? n) 1 (* n (factorial (sub1 n)))))
(define (find-e accuracy sum)
(if (zero? accuracy) (add1 sum)
(find-e (sub1 accuracy) (+ sum (/ 1 (factorial accuracy))))))
(display (format "~f" (find-e 100 0)))
let rec factorial n = if n == 0 then 1 else n * factorial (n - 1) ;;
let rec find_e accuracy sum =
if accuracy == 0
then (sum + 1)
else find_e (accuracy - 1) (sum + (1 / factorial accuracy)) ;;
let result = find_e 100 0 ;;
我记得,scheme 有一个“数值塔”,试图防止您在数值计算中失去准确性。
OCaml 没有任何花哨的数字自动处理功能。您的代码使用类型 int
,这是一个固定大小的整数(在通常的实现中为 31 或 63 位)。因此,在几乎所有情况下,您的表达式 1 / factorial accuracy
都将为 0,并且 factorial accuracy
的值对于除最小值以外的所有值都是不可表示的。 factorial 100
的值将是 0
因为它是 2^63:
的倍数
# let rec fact n = if n < 2 then 1 else n * fact (n - 1);;
val fact : int -> int = <fun>
# fact 100;;
- : int = 0
您的代码中没有浮点数,因此不可能有任何混合。但是 OCaml 一开始就不允许混合。这是一种强类型语言,其中 int
和 float
是两种不同的类型。
这是您转换为使用浮点数的代码:
let rec factorial n =
if n = 0.0 then 1.0 else n *. factorial (n -. 1.0)
let rec find_e accuracy sum =
if accuracy = 0.0 then
sum +. 1.0
else
find_e (accuracy -. 1.0) (sum +. 1.0 /. factorial accuracy)
let result = find_e 100.0 0.0
如果我 copy/paste 将其放入 OCaml REPL(也称为“顶层”),我会看到:
val factorial : float -> float = <fun>
val find_e : float -> float -> float = <fun>
val result : float = 2.71828182845904509
作为旁注,OCaml 中的相等比较运算符是 =
。不要使用 ==
进行比较。这是一个完全不同的运算符:
# 1.0 == 1.0;;
- : bool = false
这个答案是对当前接受的答案的补充。
由于阶乘是整数值,使用浮点数来表示计算有点不幸,因为它会导致足够大的值的精度损失。 Scheme 和 Lisp 对 bignums 和 ratios 有透明的支持,但是 OCaml 有一个库。
opam install zarith
然后在你的 ocaml 顶层:
# #use "topfind";;
# #require "zarith";;
/home/user/.opam/4.11.0/lib/zarith: added to search path
/home/user/.opam/4.11.0/lib/zarith/zarith.cma: loaded
有两个主要模块,Z 和 Q(整数和有理数),以及一个旧的大整数模块的兼容模块。您可能想查看文档:https://antoinemine.github.io/Zarith/doc/latest/Z.html
库定义了自己的整数类型:
# Z.of_int(3);;
- : Z.t = <abstr>
如果你安装了 pretty-printer:
# #install_printer Z.pp_print;;
# Z.of_int(3);;
- : Z.t = 3
同样,Q 模块可以帮助计算分数。您可能可以通过这种方式在 OCaml 中实现代码的等效版本。
我今天开始学习OCaml。我已经知道 Scheme,所以我认为尝试将一些示例 Scheme 程序转换为 ML 会很好。我在下面有一些代码用于计算有效的欧拉数,但它在 OCaml 中不起作用。我得到这个错误:Exception: Division_by_zero.
我认为这可能是在某处混合浮点数和整数的问题。我无法弄清楚如何使用 ocamldebug
为函数设置断点。任何人都可以确定我的错误发生在哪里吗?谢谢。
(define (factorial n)
(if (zero? n) 1 (* n (factorial (sub1 n)))))
(define (find-e accuracy sum)
(if (zero? accuracy) (add1 sum)
(find-e (sub1 accuracy) (+ sum (/ 1 (factorial accuracy))))))
(display (format "~f" (find-e 100 0)))
let rec factorial n = if n == 0 then 1 else n * factorial (n - 1) ;;
let rec find_e accuracy sum =
if accuracy == 0
then (sum + 1)
else find_e (accuracy - 1) (sum + (1 / factorial accuracy)) ;;
let result = find_e 100 0 ;;
我记得,scheme 有一个“数值塔”,试图防止您在数值计算中失去准确性。
OCaml 没有任何花哨的数字自动处理功能。您的代码使用类型 int
,这是一个固定大小的整数(在通常的实现中为 31 或 63 位)。因此,在几乎所有情况下,您的表达式 1 / factorial accuracy
都将为 0,并且 factorial accuracy
的值对于除最小值以外的所有值都是不可表示的。 factorial 100
的值将是 0
因为它是 2^63:
# let rec fact n = if n < 2 then 1 else n * fact (n - 1);;
val fact : int -> int = <fun>
# fact 100;;
- : int = 0
您的代码中没有浮点数,因此不可能有任何混合。但是 OCaml 一开始就不允许混合。这是一种强类型语言,其中 int
和 float
是两种不同的类型。
这是您转换为使用浮点数的代码:
let rec factorial n =
if n = 0.0 then 1.0 else n *. factorial (n -. 1.0)
let rec find_e accuracy sum =
if accuracy = 0.0 then
sum +. 1.0
else
find_e (accuracy -. 1.0) (sum +. 1.0 /. factorial accuracy)
let result = find_e 100.0 0.0
如果我 copy/paste 将其放入 OCaml REPL(也称为“顶层”),我会看到:
val factorial : float -> float = <fun>
val find_e : float -> float -> float = <fun>
val result : float = 2.71828182845904509
作为旁注,OCaml 中的相等比较运算符是 =
。不要使用 ==
进行比较。这是一个完全不同的运算符:
# 1.0 == 1.0;;
- : bool = false
这个答案是对当前接受的答案的补充。
由于阶乘是整数值,使用浮点数来表示计算有点不幸,因为它会导致足够大的值的精度损失。 Scheme 和 Lisp 对 bignums 和 ratios 有透明的支持,但是 OCaml 有一个库。
opam install zarith
然后在你的 ocaml 顶层:
# #use "topfind";;
# #require "zarith";;
/home/user/.opam/4.11.0/lib/zarith: added to search path
/home/user/.opam/4.11.0/lib/zarith/zarith.cma: loaded
有两个主要模块,Z 和 Q(整数和有理数),以及一个旧的大整数模块的兼容模块。您可能想查看文档:https://antoinemine.github.io/Zarith/doc/latest/Z.html
库定义了自己的整数类型:
# Z.of_int(3);;
- : Z.t = <abstr>
如果你安装了 pretty-printer:
# #install_printer Z.pp_print;;
# Z.of_int(3);;
- : Z.t = 3
同样,Q 模块可以帮助计算分数。您可能可以通过这种方式在 OCaml 中实现代码的等效版本。