이것은 http://programmers.blogoverflow.com/2012/08/20-controversial-programming-opinions/ 에서 온다
"Pi는 더 많은 용어를 사용하여 4 * (1 – 1/3 + 1/5 – 1/7 +…) 함수를 사용하여 Pi를 추정 할 수 있으므로 Pi를 소수점 5 자리의 정확도로 계산하는 함수를 작성하십시오. "
- 추정은 상기 주어진 순서를 계산하여 수행되어야한다.
이것은 http://programmers.blogoverflow.com/2012/08/20-controversial-programming-opinions/ 에서 온다
"Pi는 더 많은 용어를 사용하여 4 * (1 – 1/3 + 1/5 – 1/7 +…) 함수를 사용하여 Pi를 추정 할 수 있으므로 Pi를 소수점 5 자리의 정확도로 계산하는 함수를 작성하십시오. "
답변:
ES6 업데이트 : 5 년이 지난 지금 더 많은 기능이 제공되고 있습니다.
let f=(i=0,a=0)=>i>1e6?a:f(i+4,a+8/-~i/(i+3))
이 버전 ( 45 바이트, 예, let
필수)은 이론적으로 ES6 엄격 모드 에서 작동합니다 . 실제로는 V8 (예 : 노드)에서 --use-strict --harmony-tailcalls
; 적절한 Tailcalls 기능은 아직 널리 구현되지 않았습니다. 그러나 동작이 지정되었으므로 괜찮습니다.
광범위하게 구현 된 것을 고수하고 엄격 모드가 필요하지 않은 경우 함수에 ES6 fat-arrow 구문을 사용하지만 48 바이트 의 비용으로 이전과 동일한 구현을 유지할 수 있습니다 (Brian H가 제안 함) .
a=>{for(a=i=0;i<1e6;a+=8/++i/~-(i+=3));return a}
단일 매개 변수의 이름 선택은 실제로 중요 하지 않지만 전역 범위 오염을 최소화하기 위해 사용하는 이름 중 하나를 선택할 수도 있습니다.
function(){for(a=i=0;i<1e6;a+=8/++i/~-(i+=3));return a}
이 버전은 함수 표현식입니다. f
이름을 지정하려면 두 문자 (예 : " ")를 추가하십시오 . 이 버전은 전역 내리 쳤을 때 a
와 i
; a,i
파라미터 목록 에 " "를 추가하면이를 방지 할 수 있습니다 .
빼기의 필요성을 피하기 위해 재구성 된 버전의 알고리즘을 사용합니다.
1/1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + ...
(3/3 - 1/3) + (7/35 - 5/35) + (11/99 - 9/99) + ...
2/3 + 2/35 + 2/99 + ...
2/(1*3) + 2/(5*7) + 2/(9*11) + ...
이 조정이없는 "일반"버전은 다음과 같습니다.
function(){for(a=0,i=1;i<1e6;i+=2)a+=[,4,,-4][i%4]/i;return a}
에서의 어느 시계 64 개 62 문자.
제안에 대한 @ardnew하는 덕분에 제거하기 4*
전과 return
.
function(){for(a=i=0;i<1e6;a+=8/++i/~-(i+=3));return a} // got rid of `i+=4`; restructured
// Old versions below.
function(){for(a=0,i=1;i<1e6;i+=4)a+=8/i/-~-~i;return a} // got rid of `4*`
function(){for(a=0,i=1;i<1e6;i+=4)a+=2/i/-~-~i;return 4*a}
a+=2/i/-~-~i;return 4*a
하여 2 개의 문자를 면도 할 수 있습니다.a+=8/i/-~-~i;return a
print reduce(lambda x,p:p/2*x/p+2*10**999,range(6637,1,-2))
1000 자리를 인쇄합니다. 규정 된 반복을 사용하는 대신 다음을 사용합니다.
pi = 2 + 1/3*(2 + 2/5*(2 + 3/7*(2 + 4/9*(2 + 5/11*(2 + ...)))))
6637
(최 분모)는 다음과 같이 공식화 될 수있다 :
숫자 * 2 * 로그 2 (10)
이것은 선형 수렴을 의미합니다. 더 깊은 반복마다 pi 이진 비트가 하나 더 생성됩니다 .
경우 , 그러나, 당신이 사용하는 주장 황갈색 -1 정체성을 당신이 약간 다르게 문제에 대해가는 괜찮다면, 유사한 융합이 달성 될 수있다. 부분 합계를 살펴보면 다음과 같습니다.
4.0, 2.66667, 3.46667, 2.89524, 3.33968, 2.97605, 3.28374, ...
각각의 용어는 수렴 점의 어느 한쪽으로 앞뒤로 점프한다는 것이 명백하다; 이 시리즈는 번갈아 수렴합니다. 또한 각 용어는 이전 용어보다 수렴 점에 더 가깝습니다. 수렴 점과 관련하여 절대적으로 단조롭습니다. 이 두 속성의 조합은 두 개의 인접 항의 산술 평균이 항 자체 중 하나보다 수렴 점에 더 가깝다는 것을 의미합니다. 내가 의미하는 바를 더 잘 이해하려면 다음 이미지를 고려하십시오.
외부 계열은 원본이고 내부 계열은 각 인접 항의 평균을 취하여 구합니다. 놀라운 차이. 그러나 진정으로 주목할만한 것은이 새로운 시리즈는 또한 수렴을 번갈아 가며 수렴 점과 관련하여 단조롭습니다. 이는이 과정이 계속해서 반복 될 수 있음을 의미합니다.
확인. 그러나 어떻게?
일부 공식적인 정의. 하자 P 1 (N)이 될 N 번째의 상기 제 1 시퀀스의 기간 P 2 (N)의 될 N 번째 두 번째 시퀀스의 기간과 마찬가지로 P의 K (N) N 번째 의 용어 K 번째 정의한 바와 시퀀스 .
P 1 = [P 1 (1), P 1 (2), P 1 (3), P 1 (4), P 1 (5), ...]
P 2 = [(P 1 (1) + P 1 (2)) / 2, (P 1 (2) + P 1 (3)) / 2, (P 1 (3) + P 1 (4)) / 2, (P 1 (4) + P 1 (5)) / 2, ...]
P 3 = [(P 1 (1) + 2P 1 (2) + P 1 (3)) / 4, (P 1 (2) + 2P 1 (3) + P 1 (4)) / 4, (P 1 (3) + 2P 1 (4) + P 1 (5)) / 4, ...]
P 4 = [(P 1 (1) + 3P 1 (2) + 3P 1 (3) + P 1 (4)) / 8, (P 1 (2) + 3P 1 (3) + 3P 1 (4) + P 1 (5)) / 8, ...]
당연히,이 계수는 이항 계수를 정확하게 따르며 파스칼의 삼각형의 단일 행으로 표현 될 수 있습니다. 파스칼 삼각형의 임의의 행은 계산하기가 쉽지 않기 때문에 간단히 첫 번째 n 부분 합 을 취하고 파스칼 삼각형 의 k 번째 행의 해당 항에 각각 곱하고 2로 나눔으로써 임의로 '심층'계열을 찾을 수 있습니다. k-1 .
이런 식으로, 단지 36 번의 반복만으로 완전한 32 비트 부동 소수점 정밀도 (소수점 ~ 14 자리)를 달성 할 수 있으며,이 시점에서 부분 합은 소수점 둘째 자리에도 수렴되지 않습니다. 이것은 분명히 골프되지 않습니다 :
# used for pascal's triangle
t = 36; v = 1.0/(1<<t-1); e = 1
# used for the partial sums of pi
p = 4; d = 3; s = -4.0
x = 0
while t:
t -= 1
p += s/d; d += 2; s *= -1
x += p*v
v = v*t/e; e += 1
print "%.14f"%x
임의의 정밀도를 원하면 약간만 수정하면됩니다. 여기서 1000 자리를 다시 계산합니다 :
# used for pascal's triangle
f = t = 3318; v = 1; e = 1
# used for the partial sums of pi
p = 4096*10**999; d = 3; s = -p
x = 0
while t:
t -= 1
p += s/d; d += 2; s *= -1
x += p*v
v = v*t/e; e += 1
print x>>f+9
p 의 초기 값 은 2 10 더 크게 시작 하여 d 가 커짐에 따라 s / d 의 정수 나누기 효과에 대응 하여 마지막 몇 자릿수가 수렴하지 않습니다. 여기에도 다시 주목하십시오 .3318
숫자 * 로그 2 (10)
첫 번째 알고리즘과 동일한 반복 횟수 ( t 는 각 반복마다 2 대신 1 씩 감소 하기 때문에 절반으로 줄어듦 ) 다시 한번, 이것은 선형 수렴을 나타냅니다 : 반복 당 1 비트의 pi . 두 경우 모두, 5 자리를 계산하기 위해 1 백만 회 반복보다 약간 더 나은 할당량으로 1000 자리 pi 를 계산하려면 3318 회 반복이 필요합니다 .
4 * sum(1/(1+i*2) if not i%2 else -1/(1+i*2) for i in xrange(places*10**(places)))
P_1 = ..., P_2 = ..., P_3 = ..., P_4 = ...
"... 곱 각 해당의 용어로 kth
파스칼의 삼각형의 행과로 나누어 2^{k-1}
."대신 nth
행 2^{n-1}
?.
아르키메데스의 접근법 26 문자
N@#*Sin[180 Degree/#]&
입력이 822 일 때 기준에 도달합니다.
질문 : 그가 180 도의 죄를 어떻게 계산했는지 아는 사람이 있습니까? 난 아니야
라이프니츠의 접근 방식 (그레고리 시리즈) 32 자
이것은 문제 포즈 러가 예제로 제공 한 것과 동일한 기능입니다. 약 50 만 번의 반복으로 기준에 도달합니다.
N@4Sum[(-1)^k/(2k+1),{k,0,10^6}]
Madhava-Leibniz 접근법 37 자
이 변형은 몇 가지 문자를 더 사용하지만 9 번의 반복으로 기준에 수렴합니다!
N@Sqrt@12 Sum[(-1/3)^k/(2k+1),{k,0,9}]
float r(){float p=0,s=4,i=1E6f;while(--i>0)p+=(s=-s)/i--;return p;}
이렇게하면 올바른 순서로 숫자를 더하여 유의성 손실을 피할 수 있습니다.
while(--i>0)
에 while(i--)
2 개 문자 저장
foldr(\k->(4/(2*k+1)-))0[0..8^7]
GHCi> 폴더 (\ k-> (4 / (2 * k + 1)-)) 0 [0..8 ^ 7]
3.141593130426724
함수 이름 계산
π=foldr(\k->(4/(2*k+1)-))0[0..8^7]
float p(i){return i<1E6?4./++i-p(++i):0;}
그것은 41 자이지만 -O2
옵티마이 저가 꼬리 재귀를 제거 하도록 컴파일 해야합니다. 이것은 또한 ++
실행 순서와 관련하여 정의되지 않은 동작에 의존합니다 . 이것을 지적 해 주셔서 감사합니다. 64 비트 Linux에서 gcc 4.4.3으로 테스트했습니다.
옵티마이 저가 합계를 다시 정렬하지 않으면 가장 작은 수부터 합산되므로 유의성 손실을 피할 수 있습니다.
로 전화하십시오 p()
.
q()
아닙니다 p()
. 그리고 나는 -O2
계산 되지 않아야한다고 생각 합니다 (그러나 계산하면 필요한 공간으로 인해 4 자입니다).
p(0)
. 3.으로 문자를 저장하십시오 return++i...
. 4. 둘 ++i
은 정의되지 않은 동작을합니다.
q
-이름을 바꾼 후 다시 확인하도록 지시합니다. 필자 -O2
는 3 자로 계산 하는 일반적인 방법을 따르고 있지만 원하는 경우 메타에서 열 수 있습니다. meta.codegolf.stackexchange.com/questions/19 는 내가 찾을 수있는 유일한 관련 토론입니다. 사용중인 gcc 버전을 추가했으며로 호출 할 수 있습니다 p()
. 문자를 저장하면 최적화 프로그램이 중지되고 segfault가 제공됩니다. meta.codegolf.stackexchange.com/questions/21에
p()
- 당신은 확실히 요구하고 p()
있는 상황이 작동 할에서? 아니면 테스트에서 스택에 있었던 일입니까?
p()
vs p(0)
에 대해 약간 다른 코드를 생성하는 것처럼 보이지만 어떤 동작을 문서화하는지 모르겠으며 실제로 C 프로그래머는 아닙니다.
J, 26 자
+ / + / _ 2 ((4 _4) & %)> : + : i.100
100 개의 순서 항목에서 1e6 항목으로 이동했습니다. 또한 이제 코드 태그가 지정되어 오류없이 브라우저에서 콘솔로 복사하여 붙여 넣을 수 있습니다.
+/+/_2((4 _4)&%)\>:+:i.1e6
-/4%>:2*i.1e6
-13 자 (#jsoftware에서 b_jonas에게 감사의 -/
표시로 번갈아 가며 총계 기호로 계산하는 것이 가능하다는 사실을 알게되었습니다 . [J의 모든 연산자는 우선 순위가 같고 오른쪽 연관이므로 -/ 1 2 3 4
<=> 1 - (2 - (3 - 4))
<=> 1 - 2 + 3 - 4
.])
def f(n,k=n)k>0?(f(n,k-1)+f(n+1,k-1))/2:n<0?0:f(n-1,0)+(-1)**n/(2*n+1.0)end;4*f(9)
사용해보십시오 : https://repl.it/LQ8w
이 접근법은 수치 가속 방식을 사용하여 주어진 시리즈를 간접적으로 사용합니다. 결과 출력은
pi ≈ 3.14159265161
vs.
pi = 3.14159265359
로 시작
f(n,0) = 1/1 - 1/3 + 1/5 - ... + ((-1)**n)/(2*n+1)
그리고 이것이 교대로 나타나기 때문에
f(n,1) = (f(n,0) + f(n+1,0))/2
그리고 이것을 반복해서 적용합니다.
f(n,k) = (f(n,k-1) + f(n+1,k-1))/2
그리고 간단하게하기 위해 f(n) = f(n,n)
.
정말로 오랫동안 달리기를 좋아하지 않는다면 간단히 사용할 수 있습니다.
def f(n)n<0?0:f(n-1)+(-1)**n/(2*n+1.0)end;4*f(1e7)
또는
a=0;for k in 0..1e7 do a+=(-1)**k/(2*k+1.0)end;4*a
float p,b;void main(a){b++<9e6?p+=a/b++,main(-a):printf("%f\n",4*p);}
a
1로 초기화 됨).void main
이상하고 비표준이지만 작동합니다. 이것이 없으면 재귀가 실제 호출로 구현되어 스택 오버플로가 발생합니다. 대안은을 추가하는 것 return
입니다.4*
세 개의 명령 행 매개 변수로 실행하는 경우 두 개의 문자 를 저장할 수 있습니다.int main(a)
하거나 심지어 main(a)
는 GCC 만 경고를 제공 할 수 있습니다. 그리고 그것은 void main
어쨌든 경고를 줄 것입니다. 어쩌면에 대한 단 하나의 주장 만 있기 때문일 것 main
입니다.
(fn [](* 4(apply +(map #(*(Math/pow -1 %1)(/ 1.0(+ 1 %1 %1)))(range 377000)))))
이것은 인수가없는 함수를 생성하여 pi를 소수점 다섯 자리까지 정확하게 근사하는 float를 계산합니다. 참고이하지 않습니다 바인드 것을 같은 이름으로 기능 pi
이 코드는 하나 제자리에 평가해야하므로 eval
으로 (<code>)
또는의 해결책이있는 경우 이름에 바인드
(defn p[](* 4(apply +(map #(*(Math/pow -1 %1)(/ 1.0(+ 1 %1 %1)))(range 377000)))))
82 자
(defn nth-term-of-pi [n] (* (Math/pow -1 n) (/ 1.0 (+ 1 n n))))
(defn pi [c] (* 4 (apply + (map nth-term-of-pi (range c)))))
(def pi-accuracy-constant (loop [c 1000] (if (< (pi c) 3.14159) (recur (inc c)) c)))
; (pi pi-accuracy-constant) is then the value of pi to the accuracy of five decimal places
<?for($j=$i=-1;1e6>$j;){$p+=($i=-$i)/($j+=2);}echo$p*4;
알고리즘 규칙을 위반하지 않고 훨씬 더 작아 질 수 있다는 것을 모르겠습니다.
<?for(;1e6>$j;)$p+=($i=-$i|4)/~-$j+=2;echo$p;
피터 테일러의 결과를 이길 수는 없지만 여기에 내 것이 있습니다.
double d(){float n=0,k=0,x;while(n<9E5){x=1/(1+2*n++);k+=(n%2==0)?-x:x;}return 4*k;}
언 골프 버전 :
double d() {
float n = 0, k = 0, x;
while (n < 9E5) {
x = 1 / (1 + 2 * n++);
k += (n % 2 == 0) ? -x : x;
}
return 4 * k;
}
편집 : 삼항 연산자를 사용하여 몇 문자를 저장했습니다.
Meh, 나의 python-fu는 충분히 강하지 않다. 더 이상 지름길을 볼 수 없지만 숙련 된 골퍼가 여기에서 다듬을 무언가를 찾을 수 있습니까?
t=s=0
k=i=1
while t<1e6:t,s,i,k=t+1,k*4./i+s,i+2,-k
4.
-> 4
) 를 위해 1 바이트를 저장할 수 있습니다 . 다른 소식으로, 방금 코드 골프에서 Python 3이 Python 2를이기는 사례를 발견했습니다!
루비-54 자
def a()p=0;1000000.times{|i|p+=8/(4*i*(4*i+2))};p;end;
콘솔에서의 첫 시도
def a()i=1;p=0;while i<2**100 do p+=8/(i*(i+2));i+=4;end;p;end;
63 자
def a;
대신을 사용하여 바이트를 저장할 수 있습니다 def a()
.
$y=1e4;for$x(0..1e4-1){$y--while sqrt($x**2+$y**2)>1e4;$a+=$y}print 4*$a/1e8
(결과 : 3.14159052)
가능한 가장 짧은 해결책은 아니지만 아마도 흥미 롭습니다. 기하학적입니다. 원 아래 면적을 계산합니다.
또 다른 재미있는 접근법이 있지만 실제로 느립니다. 사각형의 분기 원 아래에있는 불연속 점의 수를 계산하고 그로부터 pi를 계산합니다.
$i=shift;for$x(0..$i){for$y(0..$i){$h++if sqrt($x**2+$y**2)<$i}}print$h*4/$i**2
명령 행 인수로 반복 횟수를 예상합니다. 여기서 런타임이 정확도와 어떤 관련이 있는지 확인할 수 있습니다. ;)
$ time perl -e '$i=shift;for$x(0..$i){for$y(0..$i){$h++if sqrt($x**2+$y**2)<$i}}print$h*4/$i**2' 100
3.1796
real 0m0.011s
user 0m0.005s
sys 0m0.003s
$ time perl -e '$i=shift;for$x(0..$i){for$y(0..$i){$h++if sqrt($x**2+$y**2)<$i}}print$h*4/$i**2' 1000
3.14552
real 0m0.354s
user 0m0.340s
sys 0m0.004s
$ time perl -e '$i=shift;for$x(0..$i){for$y(0..$i){$h++if sqrt($x**2+$y**2)<$i}}print$h*4/$i**2' 10000
3.14199016
real 0m34.941s
user 0m33.757s
sys 0m0.097s
DECLARE @B int=3, @A varchar(max), @C varchar(max)='1'
WHILE @B<100000
BEGIN
SELECT @C=@C+(select case when (@B-1)%4=0 then'+'else'-'end)+
(SELECT cast(cast(1.0/@B as decimal(9,8)) as varchar(max)))
SELECT @B=@B+2
END
EXECUTE('SELECT 4*('+@C+')')
SQL Fiddle을 제공하지만 1/3 1/5 1/7 등 분수를 찾는 데 너무 많은 루프가 들어가고 오류 lol이 발생합니다. 변경할 경우, @B<100000
에 1000
그것은 (정확도 자릿수 같은 번호로 분명하지)를 실행합니다.
p08p109p^v*86%+55:<$$$<
\$\>:#,_@>+\55+/:#^_"."
v>p"~"/:"~"%08p"~"/00p:2\4%-*"(}"
8^90%"~":+2:+g90*+g80*<
>*:**\/+>"~~"00g:"~"`!|
누군가 궁금해하는 경우 코끼리입니다.
p=lambda:3.14159