Erlang编程和计算pi的新方法

Erlang编程和计算pi的新方法,erlang,pi,Erlang,Pi,我对erlang(以及一般的编程)是全新的。所以我试图让Erlang精确地输出π的计算结果,精确到小数点后5位。我已经连续5天(大概35个小时)尝试不同的东西和研究,但我就是想不出来。以下是我的思考过程和迄今为止所做的工作: 注意:我想先从小一点的开始(精确到2个小数),然后我想一旦我能把它调整到2,我就可以调整到5个小数 -module (difpi). -export [(sumpi1/2)]. -export [(sumpi2/2)]. sumpi1(628,_) -> 0;

我对erlang(以及一般的编程)是全新的。所以我试图让Erlang精确地输出π的计算结果,精确到小数点后5位。我已经连续5天(大概35个小时)尝试不同的东西和研究,但我就是想不出来。以下是我的思考过程和迄今为止所做的工作:

注意:我想先从小一点的开始(精确到2个小数),然后我想一旦我能把它调整到2,我就可以调整到5个小数

-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))))).
က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> 
因此,通过4*(1-1/3+1/5-1/7…)之和使用pi近似值,您可以使用更多的术语准确地得到pi值。我试图做的是让它在正确到达所需的小数点时停止递归。现在我已经能够通过反复试验计算出精确到1,2,3,4,5,6位小数的项数,但是我试图得到一个通用的方法,因为我们假设你不知道π的值

所以我要做的是让erlang提出两个求和…一个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))))).
က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> 
我能算出628个术语达到314个,628个术语也达到314个,但我如何在不“知道”还有多少术语的情况下让它达到314个呢

所以我想让它说。。。1个学期后的sumPi1和前2个学期后的sumPi2……它们匹配吗(否),那么现在sumPi1前2个学期和sumPi2前3个学期……它们匹配吗?(没有)。。。但我希望这个过程继续下去,直到它们匹配为止,然后我希望输出显示ok,它们匹配,它们匹配314

如您所见,我内置了2个参数,以便运行它并输入它可以到达的小数位数。所以我可以说,计算π到1,2,3…等等。(尽管我只需要将其设置为5,但我认为这样做会很酷)

我希望我的问题有意义。如果可以的话请帮忙,我的大脑快要爆炸了

下面是输出结果,显示截断的628和629项匹配(显然,只需除以10^2,得到3.14,以2位小数显示)


恭喜你接受学习二郎的任务。这真是一种迷人的编程语言,运行在迷人的虚拟机之上

只要有一点模式匹配的帮助,就完全有可能解决这个问题。在进一步迭代之前,您必须采用保留计算的最后结果并将其与当前步骤进行比较的策略

这类级数收敛速度非常慢,因此需要特别注意使用尾部调用优化,这意味着对函数的递归调用必须是函数本身的最后一条也是唯一一条语句

我的执行建议如下。您可以通过以下简单的单元测试来证明它是有效的:

%%% 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.

谢谢现在我只需要看看它是如何工作的以及所有的语法。谢谢你的帮助!再次感谢你的帮助。我终于能够在不使用case的情况下让它做我需要它做的事情(我还没有做到这一点,只是从递归开始)。但是看到你的代码,以及某种“病态”和看着它工作是非常宝贵的!嘿@chitown88,不客气!如果你能在这里发布你的最终解决方案,作为你自己问题的答案,那就太好了。如果你能接受我的回答,我也会很高兴,因为这是唯一的答案,而且证明它很有帮助。:)