Raku를 사용하여 e 번호 계산


9

수식 을 계산하여 e 상수 ( AKA Euler 's Number )를 계산 하려고합니다.이자형

한 번에 계승과 나눗셈을 계산하기 위해 다음과 같이 썼습니다.

my @e = 1, { state $a=1; 1 / ($_ * $a++) } ... *;
say reduce  * + * , @e[^10];

그러나 그것은 효과가 없었습니다. 올바르게하는 방법?


"어떻게 작동하지 않았습니까?"
SherylHohman

1
계승을 구성하려는 시도에서 이전 값 $_ 변수를 사용했기 때문에 샘플 코드의 분모 부분이 제대로 작동하지 않았습니다 . 분명히 중복되었습니다. 아래의 올바른 해결책 $_에서 떨어졌고 완벽하게 해결되었습니다.
Lars Malmsteen

감사. 나는 그 진술이 정확히 무엇을 의미하는지 더 많이 찾고 있다고 생각합니다. 오류가 있었 듯이, 당신이 기대했던 것과 일치하지 않는 것은 그런 종류였습니다. 귀하의 계산이 해당 계산에 대한 알려진 답변과 일치하지 않습니다. 다행 이네요! 또한 실제 문제가 무엇인지에 대한 훌륭한 답변 후 설명 :-)
SherylHohman

답변:


11

코드 분석 섹션에서 코드를 분석합니다 . 그 전에 나는 보너스 자료의 몇 가지 재미있는 섹션을 제시합니다.

하나의 라이너 하나의 문자 1

say e; # 2.718281828459045

"다양한 방법에 관한 논문" 2

위의 링크를 클릭하면 Damian Conway의 eRaku 컴퓨팅 관련 특별 기사를 볼 수 있습니다.

이 기사는 많은 재미가 있습니다 (결국 데미안입니다). 컴퓨팅에 대한 매우 이해하기 쉬운 토론입니다 e. 그리고 Larry Wall이 후원 한 TIMTOWTDI 철학에 대한 Raku의 중탄산염 환생에 경의를 표합니다.

애피타이저로서 기사의 중간 쯤에서 인용 한 내용은 다음과 같습니다.

이러한 효율적인 방법은 모두 무한한 일련의 항을 합산하여 동일한 방식으로 작동한다는 점을 감안할 때 우리에게 그렇게하는 기능이 있다면 더 좋을 것입니다. 그리고 함수가 자체적으로 정확한 답을 얻기 위해 실제로 포함해야 할 시리즈의 초기 서브 세트의 양을 계산할 수 있다면 더 좋을 것입니다. 그것을 발견하기 위해 여러 번의 시도.

그리고 Raku에서와 마찬가지로, 우리가 필요로하는 것을 구축하는 것은 놀랍도록 쉽습니다.

sub Σ (Unary $block --> Numeric) {
  (0..∞).map($block).produce(&[+]).&converge
}

코드 분석

시리즈를 생성하는 첫 번째 라인은 다음과 같습니다.

my @e = 1, { state $a=1; 1 / ($_ * $a++) } ... *;

클로저 ( { code goes here })는 항을 계산합니다. 클로저에는 암시 적 또는 명시적인 서명이 있으며,이를 통해 인수의 수를 결정합니다. 이 경우 명시적인 서명이 없습니다. 의 사용 $_( 은 "주제"변수 에 바인딩 된 하나 개의 인수가 필요합니다 암시 서명의) 결과 $_.

시퀀스 연산자 ( ...)를 반복하는, 폐쇄의 인수로 이전 용어를 통과, 그 왼쪽의 폐쇄를 호출 게으르게 이 경우에 오른쪽에 엔드 포인트까지 용어의 시리즈를 구축 *, 속기에 대한 Inf일명 무한대.

클로저에 대한 첫 번째 호출 주제는 1입니다. 따라서 클로저 1 / (1 * 1)는 시리즈의 처음 두 항을로 계산하여 반환합니다 1, 1/1.

의 주제 번째 호출이 이전의 값, 1/1즉, 1다시. 따라서 클로저는 계산하고 반환 1 / (1 * 2)하여 시리즈를 확장합니다 1, 1/1, 1/2. 모두 좋아 보인다.

다음 폐쇄로 계산 1 / (1/2 * 3)이다 0.666667. 그 용어는이어야합니다 1 / (1 * 2 * 3). 죄송합니다.

코드가 수식과 일치하도록 만들기

귀하의 코드는 공식과 일치해야합니다.
이자형

이 수식에서 각 항은 계열에서의 위치 를 기반으로 계산됩니다 . 일련 의 k 번째 항 (여기서 k = 0 인 경우 1)은 계승 k 의 역수입니다.

(따라서 이전 기간 의 가치 와는 아무런 관련이 없습니다 . 따라서 이전 기간 $_가치 를받는을 폐쇄에 사용해서는 안됩니다.)

계승 접미사 연산자를 만들어 봅시다 :

sub postfix:<!> (\k) { [×] 1 .. k }

(접근 ×곱셈 연산자로, 일반적인 ASCII 접두사의 유니 코드 별칭 이 더 *좋습니다.)

그것은 속기입니다 :

sub postfix:<!> (\k) { 1 × 2 × 3 × .... × k }

(중괄호 안에 의사 메타 신택 틱 표기법을 사용하여 필요한만큼 많은 단어를 더하거나 빼는 아이디어를 표시했습니다.

보다 일반적으로, op식 시작 부분에 대괄호 안에 대입 연산자 를 넣으면에 해당하는 접두사 연산자가 형성 reduce with => &[op],됩니다. 자세한 내용은 축소 메타 오퍼레이터 를 참조하십시오.

이제 새로운 factorial postfix 연산자를 사용하여 클로저를 다시 작성할 수 있습니다.

my @e = 1, { state $a=1; 1 / $a++! } ... *;

빙고. 이것은 올바른 시리즈를 생성합니다.

... 그렇지 않을 때까지 다른 이유로. 다음 문제는 숫자 정확도입니다. 그러나 다음 섹션에서 다루겠습니다.

코드에서 파생 된 하나의 라이너

아마도 세 줄을 하나로 압축하십시오.

say [+] .[^10] given 1, { 1 / [×] 1 .. ++$ } ... Inf

.[^10]에 의해 설정된 주제에 적용됩니다 given. (의 ^10줄임말로 0..9, 위의 코드는 시리즈에서 처음 10 개의 항의 합을 계산합니다.)

나는 $a다음 학기에서 폐쇄 계산을 제거했습니다 . 고독 $(state $)익명 상태 스칼라 와 동일 합니다. 을 (를) 초기화 $a하여 수행 한 것과 동일한 효과를 얻기 위해 사후 증분 대신 사전 증분으로 만들었습니다 1.

우리는 이제 아래의 의견에서 당신이 지적한 최종 (큰!) 문제가 남았습니다.

피연산자 중 어느 것도 Num(float이므로 근사값) 인 경우, /연산자는 일반적으로 100 % 정확함 Rat(제한된 정밀도 합리적)을 반환합니다 . 그러나 결과의 분모가 64 비트를 초과하면 그 결과는 Num정확도로 성능을 교환하고 싶지 않은 트레이드 오프 로 변환됩니다 . 우리는 그것을 고려해야합니다.

무제한 정밀도 와 100 % 정확도 를 지정하려면 FatRats 를 사용하도록 연산을 강제 실행하십시오 . 제대로 이렇게하려면, 단지하게 (적어도) 피연산자 중 하나가 될 FatRat(그리고 아무도 다른 사람은 수 Num) :

say [+] .[^500] given 1, { 1.FatRat / [×] 1 .. ++$ } ... Inf

이것을 십진수 500으로 확인했습니다. Raku 언어 또는 Rakudo 컴파일러의 한계를 초과하여 프로그램이 충돌 할 때까지 정확하게 유지 될 것으로 기대합니다. ( 내가 그것에 대한 토론을 위해 65536 비트 너비의 bigint를 원시 정수로 개봉 할 수 없다는 대답을 참조하십시오 .)

각주

1 라쿠 포함, 내장 된 몇 가지 중요한 수학적 상수가 e, i그리고 pi(그 별명 π). 따라서 수학 책과 비슷하게 라쿠 어로 오일러의 정체성을 쓸 수 있습니다. 오일러의 정체성에 대한 RosettaCode의 Raku 항목에 대한 크레딧으로 :

# There's an invisible character between <> and i⁢π character pairs!
sub infix:<⁢> (\left, \right) is tighter(&infix:<**>) { left * right };

# Raku doesn't have built in symbolic math so use approximate equal 
say e**i⁢π + 1 ≅ 0; # True

2 Damian의 기사는 반드시 읽어야합니다. 그러나 'raku "euler 's number" 에 대한 Google 의 100 개 이상의 경기 중 하나 인 훌륭한 치료법 중 하나 일뿐 입니다.

3 python 팬이 작성한 TIMTOWTDI의보다 균형 잡힌 견해 중 하나는 TIMTOWTDI와 TSBO-APOO-OWTDI 를 참조하십시오 . 그러나 TIMTOWTDI를 너무 멀리 가져 가면 단점 이 있습니다 . 이 후자의 "위험"을 반영하기 위해 Perl 커뮤니티는 유머러스하게 길고 읽을 수없고 절제된 TIMTOWTDIBSCINABTE를 만들어 냈습니다. 한 가지 이상의 방법이 있지만 때로는 일관성이 나쁜 것은 아닙니다. 이상하게도 Larry는 중탄산염을 Raku 디자인에 적용했고 Damian은이를 Raku의 컴퓨팅 e에 적용했습니다 .


응답 해주셔서 감사합니다. 당신의 길에 근거한 나의 길이 라는 제목의 섹션은 그것을 아주 잘 해결합니다. 그래도 복잡한 부분을 찾아봐야합니다. 나는 평원 $이 속기 라는 것을 몰랐다 state $. 그것은 매우 편리하다.
Lars Malmsteen

의 자리의 수를 지정하는 방법이 있나요 e3 솔루션은 (제목 당신의 방법에 내 방식을 기반으로 )? 1에서 다음에 FatRat (500)을 추가하려고 시도했습니다. ... given 1.FatRat(500), ...숫자를 500 자리의 정밀도로 만들기 위해 작동하지 않았습니다.
Lars Malmsteen

@LarsMalmsteen FatRat마지막 섹션에서 귀하의 매우 중요한 질문을 해결했습니다 . 또한 유일한 주요 변경 사항은 FatRat물건 이지만 전체 답변을 연마했습니다 . (, BTW 내 대답의 대부분은 원래의 질문에 정말 접선 실감 나는 당신이 자신을 즐겁게하고 아마도 나중에 독자에게 재미있을 모든 여분의 보풀을 쓰는 저를 신경 쓰지 않았다 신뢰합니다.)
raiph

추가 노력에 감사드립니다. 따라서 .FatRat확장은 코드 생성기 안에 넣어야합니다. 이제이 FatRat방법 으로 추가 하고 1000 + 자릿수 정밀도로 e 를 계산했습니다 . 여분의 보풀이 추가됩니다. 예를 들어 나는 say긴 배열 / 시퀀스를 자르고 있다는 것을 몰랐습니다 . 이러한 정보는 잘 알고 있습니다.
Lars Malmsteen

@LarsMalmsteen :) " .FatRat확장자는 코드 생성기 안에 넣어야합니다." 예. 더 일반적으로, 나눗셈과 관련된 표현이 이미 평가 된 경우, Rat정밀도가 넘치면 발생하는 손상을 취소하기에는 너무 늦습니다 . 이 경우, 그것은으로 평가합니다 Num(플로트)과 회전 taints에 더 계산을하고, 그것을 포함하는 것으로 Num . 일의 체류를 위해 할 수있는 유일한 방법은 FatRat것입니다 시작FatRat하고 피 Num들. Raku에 s 를 고수하도록 알리는 것이 하나 이상 있다면 Ints와 Rats는 정상 입니다. FatRatFatRat
raiph

9

에 분수가 $_있습니다. 따라서 당신은 1 / (1/$_ * $a++)또는 오히려 필요합니다 $_ /$a++.

Raku에서는이 계산을 단계별로 수행 할 수 있습니다

1.FatRat,1,2,3 ... *   #1 1 2 3 4 5 6 7 8 9 ...
andthen .produce: &[*] #1 1 2 6 24 120 720 5040 40320 362880
andthen .map: 1/*      #1 1 1/2 1/6 1/24 1/120 1/720 1/5040 1/40320 1/362880 ...
andthen .produce: &[+] #1 2 2.5 2.666667 2.708333 2.716667 2.718056 2.718254 2.718279 2.718282 ...
andthen .[50].say      #2.71828182845904523536028747135266249775724709369995957496696762772

좋은. 나는 전혀 몰랐다 andthen.
홀리
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.