我是erlang的新手(以及一般的编程)。因此,我试图让Erlang准确精确地输出Pi的计算,精确到5位小数。我花了大约连续5天(大约35个小时)尝试不同的事情并进行研究,但我无法弄明白。这是我的思考过程和迄今为止我所完成的工作:
注意:我想从较小的东西(准确到2位小数)开始,并想一旦我可以得到2,我可以调整到达到5位小数。
因此,使用4 *(1 - 1/3 + 1/5 - 1/7 ...)求和的pi近似,您可以使用更多的术语准确地获得pi的值。我想要做的是让它在正确到达所需小数的那一刻停止递归。现在我已经能够通过反复试验来确定准确地获得1,2,3,4,5,6个小数的多少个术语,但是我试图找到一个通用的方法来做到这一点因为我们假设你不知道pi的价值。
所以我试图做的是让erlang得出2个求和... N个项的总和和N + 1个项的总和,以及N的总和金额与下一个金额(N + 1)的总和相匹配,它应该停止并输出该匹配值。
我想到它的方式,因为我无法截断到某个小数,我可以截断为整数...所以求和的乘数乘以10 ^ P(其中P是小数位数,所以在我的例子中,P是输入2),然后截断以检查两个求和何时匹配,当它们匹配时,给出输出,我可以将它除以10 ^ P得到小数。
-module (difpi).
-export [(sumpi1/2)].
-export [(sumpi2/2)].
sumpi1(628,_) -> 0;
sumpi1(N,P) -> trunc((((math:pow(-1,N))*(4*(math:pow(10,P))/(2*N+1)) + (sumpi1(N+1,P))))).
sumpi2(628+1,_) -> 0;
sumpi2(K,P) -> trunc((((math:pow(-1,K))*(4*(math:pow(10,P))/(2*K+1)) + (sumpi2(K+1,P))))).
我能够弄清楚花了628个术语到达314,第628个术语也是314,但是如果没有"知道"我怎么做呢?有多少条款要去?
所以我试图让它说...一个学期后的sumPi1和第一个2个学期后的sumPi2 ...它们匹配(NO),所以现在sumPi1前2个术语,sumPi2前3个术语......他们匹配吗? (NO)...但是我希望这个过程继续进行,直到它们匹配为止,然后我希望输出说好,但是它们匹配,并且它们在314匹配。
我建立了2个参数,你可以看到我可以运行它并输入它可以去的小数位数。所以我可以说,计算pi到1位小数,2位小数,3位......等等。 (即使我需要它只到5,只是觉得这样做很酷)。
我希望我的问题有道理。请尽可能帮助,我的大脑即将爆炸!
这里的输出是什么显示截断的第628和第629项匹配(显然只是除以10 ^ 2得到3.14以显示它为2位小数)。
ကErlang/OTP 19 [erts-8.2] [64-bit] [smp:4:4] [async-threads:10]
Eshell V8.2 (abort with ^G)
1> cd("c:/erlang").
c:/erlang
ok
2> c(difpi).
{ok,difpi}
3> difpi:sumpi1(0,2).
314
4> difpi:sumpi2(0,2).
314
5>
答案 0 :(得分:2)
恭喜您学习Erlang。它真的是一种迷人的编程语言,运行在一个迷人的虚拟机之上。
完全有可能在模式匹配的帮助下解决这个问题。您必须采用保持计算的最后结果的策略,并在进一步迭代之前将其与当前步骤进行比较。
这类序列收敛速度非常慢,因此特别注意利用尾调用优化非常重要,这意味着对函数的递归调用必须是函数本身的最后一个也是唯一的语句。
我的实施建议如下。您可以通过这个简单的单元测试来证明它的工作原理:
%%% file: diff_pi_tests.erl
-module(diff_pi_tests).
-include_lib("eunit/include/eunit.hrl").
-import(diff_pi, [sum_pi/1]).
sum_pi_test_() ->
[
?_assertEqual(3.0, sum_pi(0)),
?_assertEqual(3.1, sum_pi(1)),
?_assertEqual(3.14, sum_pi(2)),
?_assertEqual(3.141, sum_pi(3)),
?_assertEqual(3.1415, sum_pi(4)),
?_assertEqual(3.14159, sum_pi(5))
].
实施:
%%% file: diff_pi.erl
-module(diff_pi).
-export([sum_pi/1]).
-spec sum_pi(integer()) -> float().
sum_pi(Precision) ->
sum_pi(4, -4, 3, Precision).
-spec sum_pi(number(), number(), number(), integer()) -> float().
sum_pi(LastResult, Numerator, Denominator, Precision) ->
NextResult = LastResult + Numerator/Denominator,
% Uncomment the following line to see the comparison of each step
% io:format("~p ~p~n", [LastResult, NextResult]),
case compare(LastResult, NextResult, Precision) of
true ->
Magnitude = math:pow(10, Precision),
trunc(NextResult*Magnitude)/Magnitude;
false ->
sum_pi(NextResult, -1*Numerator, Denominator+2, Precision)
end.
-spec compare(number(), number(), integer()) -> boolean().
compare(X, Y, Precision) ->
RoundX = trunc(X*math:pow(10, Precision)),
RoundY = trunc(Y*math:pow(10, Precision)),
RoundX =:= RoundY.
编译并运行测试:
$ erlc *.erl && erl -noshell -s eunit test diff_pi -s init stop
All 6 tests passed.