오늘의 랜덤 골프 # 4 : 베르트랑 패러독스


19

시리즈 정보

우선, 이것을 다른 코드 골프 도전과 같이 취급하고 시리즈에 대해 전혀 걱정하지 않고 대답 할 수 있습니다. 그러나 모든 과제에는 리더 보드가 있습니다. 첫 번째 게시물에서 시리즈 대한 추가 정보와 함께 리더 보드를 찾을 수 있습니다 .

시리즈에 대한 아이디어가 많이 있지만 미래의 과제는 아직 해결되지 않았습니다. 제안 사항이 있으면 관련 샌드 박스 게시물에 알려주십시오 .

구멍 4 : 베르트랑 패러독스

버트 랜드 역설 흥미로운 문제, 어떤 프로그램 코드, 자신의 중간 점과 길이의 서로 다른 분포를 얻을 수 원에서 임의 코드를 따기위한 방법 다른 방법을.

이 과제에서는 "오른쪽"방법을 사용하여 단위 원의 임의 코드를 생성해야합니다. 링크 된 Wikipedia 기사에서 "방법 2"는 이러한 방법입니다.

정확한 규칙은 다음과 같습니다.

  • 당신은해야 하나 양의 정수N 많은 코드가 반환되는 방법을 지정합니다. 출력값은 N극점 각도 (라디안)로 표시된 단위 원의 두 점으로 지정된 코드 목록이어야합니다 .
  • 코드는 두 각도 각각에 대해 적어도 20 개의 서로 다른 값 을 반환 할 수 있어야합니다 . 사용 가능한 RNG의 범위가 더 작은 경우 먼저 내장 RNG 위에 충분히 넓은 범위의 RNG를 구축하거나 자신의 적절한 RNG를 구현해야합니다 . 이 페이지 가 도움 될 수 있습니다.
  • 코드 배포는 링크 된 Wikipedia 기사의 "Method 2"에서 생성 된 코드와 구분할 수 없어야합니다. 코드를 선택하기 위해 다른 알고리즘을 구현하는 경우 정확성 증명을 포함하십시오. 어떤 알고리즘을 구현하든 이론적으로는 단위 원에서 유효한 코드를 생성 할 수 있어야합니다 (기본 PRNG 또는 제한 정밀도 데이터 유형의 제한을 제외 함).
  • 구현시 부동 소수점 숫자 (최소 32 비트 너비) 또는 고정 소수점 숫자 (최소 24 비트 너비)를 사용하고 반환해야 하며 모든 산술 연산은 최대 16ulp 내에서 정확해야합니다 .

전체 프로그램 또는 함수를 작성하고 STDIN (또는 가장 가까운 대안), 명령 행 인수 또는 함수 인수를 통해 입력을 받고 STDOUT (또는 가장 가까운 대안), 함수 리턴 값 또는 함수 (out) 매개 변수를 통해 출력을 생성 할 수 있습니다.

개별 숫자가 명확하게 식별 가능하고 총 수가 항상 짝수 인 한 출력은 편리한 목록 또는 문자열 형식 일 수 있습니다.

이것은 코드 골프이므로 가장 짧은 제출 (바이트)이 이깁니다. 물론 사용자 당 가장 짧은 제출물도 시리즈의 전체 순위표에 들어갑니다.

심상

다음 스 니펫을 사용하여 생성 된 선을 렌더링하고 해당 분포를 검사 할 수 있습니다. 텍스트 영역에 각도 목록을 붙여 넣기 만하면됩니다. 스 니펫은 숫자가 단순한 10 진수 (과학 표기법 없음) 인 한 거의 모든 목록 형식을 처리 할 수 ​​있어야합니다. 배포에 대한 좋은 아이디어를 얻으려면 1000 줄 이상을 사용하는 것이 좋습니다. 또한 아래 기사에 제시된 다양한 방법에 대한 몇 가지 예제 데이터를 제공했습니다.

방법 1로 생성 된 예제 데이터

방법 2로 생성 된 예제 데이터

방법 3으로 생성 된 예제 데이터

리더 보드

시리즈의 첫 번째 게시물은 리더 보드를 생성합니다.

답변이 표시되도록하려면 다음 마크 다운 템플릿을 사용하여 모든 답변을 헤드 라인으로 시작하십시오.

# Language Name, N bytes

N제출물의 크기는 어디에 있습니까 ? 당신이 당신의 점수를 향상시킬 경우에, 당신은 할 수 있습니다 를 통해 눈에 띄는에 의해, 헤드 라인에 오래된 점수를 유지한다. 예를 들어 :

# Ruby, <s>104</s> <s>101</s> 96 bytes

(언어는 현재 표시되어 있지 않지만 스 니펫은이를 요구하고 구문 분석하며 향후 언어 별 리더 보드를 추가 할 수 있습니다.)

답변:


12

IA-32 기계 코드, 54 바이트

코드의 16 진 덤프 :

68 00 00 00 4f 0f c7 f0 50 db 04 24 58 d8 34 24
f7 d9 78 f1 d9 c0 dc c8 d9 e8 de e1 d9 fa d9 c9
d9 f3 dc c0 d9 eb de ca d8 c1 dd 1a dd 5a 08 83
c2 10 e2 d1 58 c3

Wikipedia에서 설명한 (약간 수정 된) 알고리즘을 사용합니다. 의사 코드에서 :

x = rand_uniform(-1, 1)
y = rand_uniform(-1, 1)
output2 = pi * y
output1 = output2 + 2 * acos(x)

I의 범위를 사용하는 -1...1것이,이 범위에서의 난수를 쉽게 만들 수 있으므로 다음 rdrand명령까지의 정수를 생성 -2^31하고 2^31-1손쉽게 2 ^ (31)에 의해 분할 될 수있다.

0...1다른 임의의 숫자 (x)에 대한 범위 를 사용해야 했습니다 acos. 그러나 음수 부분은 양수 부분과 대칭입니다. 음수는 스팬이 파이 라디안보다 큰 코드를 생성하지만 베르트랑 역설을 설명하기 위해 중요하지 않습니다.

80386 (또는 x87) 명령어 세트에는 전용 acos명령어 가 없으므로 명령어 만 사용하여 계산을 표현해야했습니다 atan.

acos(x) = atan(sqrt(1-x^2)/x)

위의 머신 코드를 생성하는 소스 코드는 다음과 같습니다.

__declspec(naked) void __fastcall doit1(int n, std::pair<double, double>* output)
{
    _asm {
        push 0x4f000000;        // [esp] = float representation of 2^32

    myloop:
        rdrand eax;             // generate a random number, -2^31...2^31-1
        push eax;               // convert it
        fild dword ptr [esp];   // to floating-point
        pop eax;                // restore esp
        fdiv dword ptr [esp];   // convert to range -1...1
        neg ecx;
        js myloop;              // do the above 2 times

        // FPU stack contents:  // x           | y
        fld st(0);              // x           | x   | y
        fmul st(0), st;         // x^2         | x   | y
        fld1;                   // 1           | x^2 | x | y
        fsubrp st(1), st;       // 1-x^2       | x   | y
        fsqrt;                  // sqrt(1-x^2) | x   | y
        fxch;                   // x           | sqrt(1-x^2) | y
        fpatan;                 // acos(x)     | y
        fadd st, st(0);         // 2*acos(x)   | y
        fldpi;                  // pi          | 2*acos(x) | y
        fmulp st(2), st;        // 2*acos(x)   | pi*y
        fadd st, st(1);         // output1     | output2
        fstp qword ptr [edx];   // store the numbers
        fstp qword ptr [edx + 8];

        add edx, 16;            // advance the output pointer
        loop myloop;            // loop

        pop eax;                // restore stack pointer
        ret;                    // return
    }
}

두 개의 난수를 생성하기 위해 코드는 중첩 루프를 사용합니다. 루프를 구성하기 위해 코드는 ecx레지스터 (외부 루프 카운터)가 양수인 것을 활용합니다. 일시적으로를 무시한 ecx다음 다시 원래 값을 복원합니다. 이 js명령 ecx은 음수 일 때 루프를 반복합니다 (정확히 한 번 발생 함).


IA32 어셈블리를 사용하는 것이 좋습니다! 간단히 말해 : 이것은 80386이 rdrand 명령이나 FP 보조 프로세서를 필요로하지 않기 때문에 엄격하게 386 기계 코드가 아닙니다
user5572685

예, IA32가 더 나은 이름입니다. 충분히 구체적이지 않지만 아마도 80386보다 더 정확할 것입니다.
anatolyg

7

Pyth, 25 23 22 바이트

rcrmn의 C ++ 11 답변 포트. 이것은 Pyth의 첫 번째 사용법이며 많은 즐거움을 얻었습니다!

VQJ,*y.n0O0.tOZ4,sJ-FJ

23 바이트 버전 :

VQJ*y.n0O0K.tOZ4+JK-JKd

folds + sum을 사용하도록 프로그램을 변경하고 J를 튜플로 설정하여 K를 제거하여 바이트를 자릅니다.

기발한:

VQJ**2.n0O0K.tO0 4+JK-JKd

@orlp 덕분에 2 바이트를 잘라냅니다.

설명:

VQ                         loop as many times as the input number
  J,                       set J to the following tuple expression
    *y.n0O0                2 * .n0 (pi) * O0 (a random number between 0 and 1)
            .tOZ4          .tOZ 4 (acos of OZ (a random number))
                 ,sJ-FJ    print the sum of J and folding J using subtraction in parenthesis, separated by a comma, followed by another newline

1
Pyth 팁 : *2_과 동일합니다 y_. 변수 Z는 처음에 0이므로을 .tO0 4작성 하여 공백을 제거 할 수 있습니다 .tOZ4.
orlp

1
25 바이트를 세고 있습니다 ...
Maltysen

또한,+JK-JK
Maltysen

@ Maltysen 둘 다 고정되었습니다. 감사!
kirbyfan64sos

@orlp 나는 단서가 없었고 y잊어 버렸습니다 Z. 결정된; 감사!
kirbyfan64sos

6

줄리아, 48 바이트

n->(x=2π*rand(n);y=acos(rand(n));hcat(x+y,x-y))

이것은 지금까지 대부분의 답변과 같이 방법 2 알고리즘을 사용합니다. 정수 입력을 받아 nx 2 배열을 반환하는 람다 함수를 만듭니다. 호출하려면 이름을 지정하십시오 (예 :) f=n->....

언 골프 + 설명 :

function f(n::Int64)
    # The rand() function returns uniform random numbers using
    # the Mersenne-Twister algorithm

    # Get n random chord angles
    x = 2π*rand(n)

    # Get n random rotations
    y = acos(rand(n))

    # Bind into a 2D array
    hcat(x+y, x-y)
end

시각화가 어떻게 보이는지 정말 좋아하므로 포함시킬 것입니다. 의 결과입니다 f(1000).

Circle


5

Pyth, 22 바이트

C ++ 답변의 포트. 나는 또 다른 23 바이트 솔루션 (지금 22!)을 가지고 있었지만 거의 최적화 된 @ kirbyfan64sos의 pyth 답변 사본이었습니다. 따라서 상자 외부에서 조금만 창의적으로 접는 연산자를 사용해야합니다.

m,-Fdsdm,y*.nZOZ.tOZ4Q

소개 후 fold 연산자의 버그로 인해 현재 작동하지 않습니다 reduce2. 풀 요청을하고 있습니다.

m             Map    
 ,            Tuple of
  -Fd         Fold subtraction on input
  sd          Fold addition on input
 m      Q     Map over range input
  ,           Tuple           
   y          Double
    *         Product
     .nZ      Pi
     OZ       [0, 1) RNG
  .t  4       Acos
    OZ        [0, 1) RNG

참고로 이것은 동일한 방식으로 작동하는 다른 솔루션이었습니다. VQKy*.nZOZJ.tOZ4,+KJ-KJ


내 사용자 이름을
잘못 입력했습니다

트윗 담아 가기 죄송합니다;)
Maltysen

4

IDL, 65 바이트

분명히 이것은 대답을 읽기 전에 독립적으로 파생하더라도 @rcrmn과 동일한 알고리즘입니다.

read,n
print,[2,2]#randomu(x,n)*!pi+[-1,1]#acos(randomu(x,n))
end

IDL의 randomu 함수는 2 19937-1 의주기를 가진 Mersenne Twister를 사용합니다 .

편집 : 위의 시각화 프로그램을 통해 1000 개의 코드를 실행했습니다. 결과의 스크린 샷은 다음과 같습니다.

IDL bertrand


4

C ++ 11, 214 바이트

#include<random>
#include<iostream>
#include<cmath>
int main(){using namespace std;int n;cin>>n;random_device r;uniform_real_distribution<> d;for(;n;--n){float x=2*M_PI*d(r),y=acos(d(r));cout<<x+y<<' '<<x-y<<';';}}

이것은 위키 백과 페이지에서 올바른 알고리즘을 직접 구현 한 것입니다 . 여기서 골프의 주요 문제는 랜덤 제너레이터 클래스가 가진 너무 긴 이름입니다. 그러나 좋은 랜드와는 대조적으로, 그것은 적어도 제대로 균일합니다.

설명:

#include<random>
#include<iostream>
#include<cmath>
int main()
{
    using namespace std;
    int n;
    cin>>n; // Input number
    random_device r; // Get a random number generator
    uniform_real_distribution<> d;   // Get a uniform distribution of 
                                     // floats between 0 and 1
    for(;n;--n)
    {
        float x = 2*M_PI*d(r),       // x: Chosen radius angle
              y = acos(d(r));        // y: Take the distance from the center and 
                                     // apply it an inverse cosine, to get the rotation

        cout<<x+y<<' '<<x-y<<';';    // Print the two numbers: they are the rotation
                                     // of the radius +/- the rotation extracted from
                                     // the distance to the center
    }
}

1
그 요소 M_PI_2는 의심스러워 보인다. 나는 그것이 1이어야한다고 생각합니다.
anatolyg

예, 완전히 해결하겠습니다. 고마워요!
rorlork

4

APL, 46 바이트

f←{U←⍵ 2⍴∊{(○2×?0)(¯1○?0)}¨⍳⍵⋄⍉2⍵⍴∊(+/U)(-/U)}

내 첫 APL 프로그램! 확실히 APL에 대한 전반적인 이해가 부족하기 때문에 크게 향상 될 수 있으므로 모든 제안이 환상적입니다. 이것은 f정수를 입력으로 취하고 방법 2를 사용하여 코드 포인트의 쌍을 계산하고 각 쌍을 줄 바꿈으로 구분하여 인쇄 하는 함수 를 만듭니다 .

당신은 할 수 있습니다 온라인으로보십시오 !

설명:

f←{ ⍝ Create the function f which takes an argument ⍵

    ⍝ Define U to be an ⍵ x 2 array of pairs, where the first
    ⍝ item is 2 times a random uniform float (?0) times pi (○)
    ⍝ and the second is the arccosine (¯1○) of another random
    ⍝ uniform float.

    U ← ⍵ 2 ⍴ ∊{(○2×?0)(¯1○?0)}¨⍳⍵

    ⍝ Create a 2 x ⍵ array filled with U[;1]+U[;2] (+/U) and
    ⍝ U[;1]-U[;2] (-/U). Transpose it into an ⍵ x 2 array of
    ⍝ chord point pairs and return it.

    ⍉ 2 ⍵ ⍴ ∊(+/U)(-/U)
}

참고 : 이전 19 바이트 솔루션은 (x + y, xy)가 아닌 (x, y)를 반환했기 때문에 유효하지 않습니다. 슬픔이 가득합니다.


3

자바, 114 바이트

n->{for(;n-->0;){double a=2*Math.PI*Math.random(),b=Math.acos(Math.random());System.out.println(a+b+" "+(a-b));}};

자바의 기본 구현. 람다 식으로 사용하십시오.

사용법 예


Math어딘가에 보관하여 크기를 줄일 수 없습니까 ? 또는 뭔가? (Java 프로그래머가 아님)
Ismael Miguel

@IsmaelMiguel 추가 2 문자가 필요합니다.
TheNumberOne

죄송합니다 : / Math표시 횟수를 줄이려고합니다 . 메타는 코드를 사용하여 다른 코드를 생성하여 문제를 해결하는 것에 대해 무엇을 말합니까?
Ismael Miguel

2
@IsmaelMiguel 공정한 게임이지만 골프보다 메타 골프에 더 능숙하다면 놀랄 것입니다.
Martin Ender

3

루비, 72 바이트

내 첫 골프! 나는 모든 사람과 같은 코드를 사용했다.

gets.chomp.to_i.times{puts"#{x=2*Math::PI*rand},#{x+2*Math.acos(rand)}"}

2

자바, 115 115123

이것은 기본적으로 다른 대부분과 동일하지만이 구멍에 대한 Java 점수가 필요하므로 여기에갑니다.

void i(int n){for(double x;n-->0;System.out.println(x+2*Math.acos(Math.random())+" "+x))x=2*Math.PI*Math.random();}

pastebin 에서 1000 개의 샘플 코드를 찾을 수 있습니다 . 다음은 한 번의 실행에서 처음 다섯 개입니다.

8.147304676211474 3.772704020731153
8.201346559916786 3.4066194978900106
4.655131524088468 2.887965593766409
4.710707820868578 3.8493686706403984
3.3839198612642423 1.1604092552846672

1

CJam, 24 22 바이트

다른 알고리즘과 마찬가지로 CJam 버전이 있습니다.

{2P*mr_1dmrmC_++]p}ri*

1000을 입력하면 다음과 같은 분포가 생성됩니다.

여기에 이미지 설명을 입력하십시오

작동 원리

알고리즘은 간단합니다 x = 2 * Pi * rand(); print [x, x + 2 * acos(rand())]

{                 }ri*        e# Run this loop int(input) times
 2P*mr                        e# x := 2 * Pi * rand()
      _                       e# copy x
       1dmr                   e# y := rand()
           mC                 e# z := acos(y)
             _++              e# o := x + z + z
                ]             e# Wrap x and o in an array
                 p            e# Print the array to STDOUT on a new line

업데이트 : Martin 덕분에 2 바이트가 절약되었습니다!

여기 사용해보십시오


1

파이썬 3, 144 117 바이트

(Blckknght 덕분에 lambda 포인터에 )

다른 방법과 동일한 방법을 사용합니다.

import math as m;from random import random as r;f=lambda n:[(x,x+2*m.acos(r()))for x in(2*m.pi*r()for _ in range(n))]

파이썬 문서에서 :

파이썬은 Mersenne Twister를 핵심 생성기로 사용합니다. 53 비트 정밀 플로트를 생성하고주기는 2 19937입니다. -1입니다.

산출

>>> f(10)
[(4.8142617617843415, 0.3926824824852387), (3.713855302706769, 1.4014527571152318), (3.0705105305032188, 0.7693910749957577), (1.3583477245841715, 0.9120275474824304), (3.8977143863671646, 1.3309852045392736), (0.9047010644291349, 0.6884780437147916), (3.333698164797664, 1.116653229885653), (3.0027328050516493, 0.6695430795843016), (5.258167740541786, 1.1524381034989306), (4.86435124286598, 1.5676690324824722)]

등등.

심상

심상


함수에 람다를 사용하고 목록 이해 (내부 생성기 표현식 사용)를 반환하면 약 20 바이트를 절약 할 수 있습니다.f=lambda n:[(x,x+2*m.acos(r()))for x in(2*m.pi*r()for _ in range(n))]
Blckknght

아, 나는 원래 람다가 있었다. 나는 목록 이해력을 두 배로 늘리는 것에 대해 생각하지 않았다고 생각합니다. 감사! @Blckknght
Zach Gates

다음과 같이 가져 오기를 수행하여 109 바이트로 단축 할 수 있습니다. tio.run/#python2
Triggernometry

1

펄, 60

#!perl -l
use Math::Trig;print$x=2*pi*rand,$",$x+2*acos rand for 1..<>

1

R, 60 56 53 49 바이트

@JayCe 덕분에 4 바이트가 추가되었으며 함수로 변경되었습니다.

다른 것과 동일한 기본 공식을 사용합니다. R은 Mersenne-Twister 방법을 기본적으로 사용하지만 다른 방법도 설정할 수 있습니다. 공백으로 구분 된 목록을 출력합니다.

function(n,y=acos(runif(n)))runif(n)*2*pi+c(y,-y)

온라인으로 사용해보십시오!


안녕하세요 Micky, x를 정의하지 않고 함수로 만들어 4 바이트절약 할 수 있습니다 .
JayCe

@JayCe 감사합니다
MickyT

0

SmileBASIC, 62 바이트

INPUT N
FOR I=1TO N
X=PI()*2*RNDF()Y=ACOS(RNDF())?X+Y,X-Y
NEXT
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.