我正在尝试制作一个程序来计算从1到100的所有数字上的Collatz序列的长度。基本上如果我有一个奇数,我必须将它乘以3并加1(n * 3 + 1) ,如果我有一个偶数,我需要将它除以2(n / 2)然后继续这样做直到它变为1并最终打印出数字被除以2或乘以的次数3并添加1。 以下是我到目前为止的情况:
let stevec = ref 0;
let n = ref 1;
for i = 1 to 100 do
n := i;
while !n != 1 do
if (n mod 2 = 0) then
stevec := !stevec + 1;
n := !n / 2;
if (n mod 2 = 1) then
stevec := !stevec + 1;
n := 3 * !n + 1;
done
print_int (stevec);
done;;
运行代码后,我得到一个语法错误,print_int得到下划线,所以我猜这有问题,但我甚至不确定。
答案 0 :(得分:3)
您的代码存在一些问题,所以我们来看看它。
let stevec = ref 0;
let n = ref 1;
你不应该编写那种代码,因为;
是一个表达式分隔符(你在这里使用它作为声明分隔符)。
正确的方法取决于您希望您的声明是本地的还是顶级的。
(* local declaration *)
let stevec = ref 0 in
let n = ref 1 in
(* toplevel declaration *)
let stevec = ref 0;;
let n = ref 1;;
然后键入while !n != 1 do
。这不应该被用来在你的整数之间进行物理不等式,而你想要结构平等。好吧,由于OCaml对整数的行为,它也会起作用,但良好做法要求您使用<>
而不是!=
。
现在让我们来看看你的循环体:
if (!n mod 2 = 0) then
stevec := !stevec + 1;
n := !n / 2;
if (!n mod 2 = 1) then
stevec := !stevec + 1;
n := 3 * !n + 1;
请注意没有任何fi
或右括号?这是因为在OCaml中,只执行then
之后的下一个表达式。 ;
的优先顺序并不像您希望的那样。您可以使用parens或更明确的begin ... end
构造。为了证明begin ... end
有效,我用else
语句替换了你的第二个测试。
if (!n mod 2 = 0) then
begin
stevec := !stevec + 1;
n := !n / 2;
end
else
begin
stevec := !stevec + 1;
n := 3 * !n + 1;
end
最后while ... done
本身就是一个表达式,你应该在它的末尾添加一个;
。
这就是你如何从代码中删除错误 然而...
这显然不是正确的方式&#34;在OCaml中做到这一点。 FP的主要特点是它与数学的接近程度,你在这里试图定义一个数学函数。因此,让我们以函数方式执行此操作:
let is_even x = (x mod 2) = 0;;
let rec collatz counter n =
if n = 1
then counter
else collatz (counter+1) (if is_even n then n/2 else 3*n+1);;
let () =
for i = 1 to 100 do
print_int (collatz 0 i);
print_newline ();
done;;
看起来不那么好吗?当然可以随意要求澄清。