Günün Rastgele Golf # 4: Bertrand Paradoksu


19

Seri Hakkında

Öncelikle, bunu diğer kod golf zorlukları gibi ele alabilir ve seri hakkında endişelenmeden cevaplayabilirsiniz. Ancak, tüm zorluklarda bir lider tablosu vardır. Liderlik tablosunu, diziyle ilgili daha fazla bilgiyi ilk gönderide bulabilirsiniz .

Dizi için sıralanmış bir sürü fikrim olmasına rağmen, gelecekteki zorluklar henüz taş değil. Herhangi bir öneriniz varsa, lütfen ilgili sandbox gönderisinde bana bildirin .

Delik 4: Bertrand Paradoksu

Bertrand paradoks ilginç bir sorun, olan Şekil telleri, bunların orta noktalarından ve uzunluklarının farklı dağılımları elde bir daire içinde rastgele kirişleri çekme ne kadar farklı yöntemler.

Bu meydan okumada, "doğru" yöntemini kullanarak, yani ölçekleme ve çeviri altında değişmeyen akorların bir dağılımını üreten birim çemberinin rastgele akorlarını üretmeniz gerekir. Bağlantılı Wikipedia makalesinde, "Yöntem 2" böyle bir yöntemdir.

İşte kesin kurallar:

  • Sen almalı bir pozitif tamsayıN birçok akor iade edilmelidir nasıl belirtir. Çıktı N, her biri birim çember üzerinde iki nokta olarak belirtilen ve radyan cinsinden kutup açılarıyla verilen akorların bir listesi olmalıdır .
  • Kodunuz , iki açının her biri için en az 20 20 farklı değer döndürebilmelidir . Mevcut RNG'nizin daha küçük bir aralığı varsa, önce yerleşik olanın üzerine yeterince geniş bir aralık ile bir RNG oluşturmanız veya kendi uygun RNG'nizi uygulamanız gerekir . Bu sayfa bunun için yararlı olabilir.
  • Akorların dağılımı, bağlantılı Wikipedia makalesinde "Yöntem 2" ile üretilenlerden ayırt edilemez olmalıdır. Akorları seçmek için farklı bir algoritma uygularsanız, lütfen bir doğruluk kanıtı ekleyin. Hangi algoritmayı uygulamayı seçerseniz seçin, teorik olarak birim çemberde geçerli bir akor oluşturabilmelidir (temel PRNG'nin veya sınırlı hassasiyetli veri türlerinin kısıtlama sınırlamaları).
  • Uygulamanız kayan noktalı sayıları (en az 32 bit genişliğinde) veya sabit noktalı sayıları (en az 24 bit genişliğinde) kullanmalı ve döndürmelidir ve tüm aritmetik işlemler en fazla 16 ulp içinde doğru olmalıdır .

Tam bir program veya işlev yazabilir ve STDIN (veya en yakın alternatif), komut satırı bağımsız değişkeni veya işlev bağımsız değişkeni ile girdi alabilir ve STDOUT (veya en yakın alternatif), işlev dönüş değeri veya işlev (çıkış) parametresi aracılığıyla çıktı üretebilirsiniz.

Bireysel sayılar açıkça ayırt edilebildiği ve toplam sayıları her zaman eşit olduğu sürece çıktı herhangi bir uygun liste veya dize biçiminde olabilir.

Bu kod golf, yani en kısa gönderme (bayt cinsinden) kazanır. Ve elbette, kullanıcı başına en kısa gönderim de serinin genel skor tablosuna girecektir.

görüntüleme

Oluşturulan hatları oluşturmak ve dağıtımlarını incelemek için aşağıdaki snippet'i kullanabilirsiniz. Metin alanına bir çift açı listesi yapıştırmanız yeterlidir. Snippet, sayılar basit ondalık sayılar olduğu sürece (bilimsel gösterim yok) hemen hemen her liste biçimini işleyebilmelidir. Dağıtım hakkında iyi bir fikir edinmek için en az 1000 satır kullanmanızı tavsiye ederim. Ayrıca, aşağıdaki makalede sunulan farklı yöntemler için bazı örnek veriler sağladım.

Yöntem 1 ile oluşturulan örnek veriler.

Yöntem 2 ile oluşturulan örnek veriler .

Yöntem 3 ile oluşturulan örnek veriler.

Liderler Sıralaması

Serinin ilk gönderisi bir skor tablosu oluşturur.

Yanıtlarınızın göründüğünden emin olmak için, lütfen aşağıdaki Markdown şablonunu kullanarak her cevaba bir başlık ile başlayın:

# Language Name, N bytes

Ngönderiminizin büyüklüğü nerede . Puanınızı artırmak varsa, olabilir onları içinden vurarak, başlığa eski hesapları tutmak. Örneğin:

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

(Dil şu anda gösterilmiyor, ancak snippet gerektiriyor ve ayrıştırıyor ve gelecekte bir dil lider tablosu ekleyebilirim.)

Yanıtlar:


12

IA-32 makine kodu, 54 bayt

Onaltılık kod:

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'nın açıkladığı (biraz değiştirilmiş) bir algoritma kullanır. Sözde kodda:

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

Aralığı kullanıyorum -1...1çünkü bu aralıkta rastgele sayılar yapmak kolay: rdrandkomut -2^31ve arasında bir tamsayı oluşturur ve 2^31-1bu da kolayca 2 ^ 31'e bölünebilir.

Ben 0...1içine beslenen diğer rasgele sayı (x) için aralığı kullanmalıydım acos; Bununla birlikte, negatif kısım pozitif kısım ile simetriktir - negatif sayılar, aralığı pi radyandan daha büyük olan akorlar üretir, ancak Bertrand paradoksunu göstermek için önemli değildir.

80386 (veya x87) komut kümesinin özel bir acostalimatı olmadığından , hesaplamayı yalnızca atantalimatı kullanarak ifade etmek zorunda kaldım :

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

Yukarıdaki makine kodunu oluşturan kaynak kodu şöyledir:

__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
    }
}

İki rasgele sayı üretmek için kod iç içe bir döngü kullanır. Döngüyü düzenlemek için kod, ecxyazmacın (dış döngü sayacı) pozitif olmasından yararlanır. Geçici olarak reddeder ecxve sonra orijinal değerini geri yüklemek için tekrar yapar. jsNe zaman talimat döngü tekrarlar ecx(bu tam olarak bir kez olur) negatiftir.


IA32 montajını kullanmak için bu cevabı beğendim! Sadece söylemek: bu kesinlikle 386 makine kodu değil 80386 Açıkçası rdrand talimat ne de gerekli bir FP yardımcı işlemci yok
user5572685

Evet, IA32 daha iyi bir isim. Yeterince spesifik değil ama muhtemelen 80386'dan daha doğru.
anatolyg

7

Pyth, 25 23 22 bayt

Bir port rcrmn'ın C ++ 11 cevabı. Bu benim ilk Pyth kullanımım ve çok eğlendim!

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

23 baytlık sürüm:

VQJ*y.n0O0K.tOZ4+JK-JKd

Katlama + toplamları kullanmak için programı değiştirerek ve K'yi kaldırarak J'yi bir tuple olarak ayarlayarak bir bayt kesin.

Orijinal:

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

@Orlp sayesinde 2 bayt kesin.

Açıklama:

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 ipuçları: *2_ile aynıdır y_. Değişken Zbaşlangıçta 0'dır, böylece alanı .tO0 4yazarak kaldırabilirsiniz .tOZ4.
orlp

1
25 bayt sayıyorum ...
Maltysen

Ayrıca, çıktıyı daha iyi biçimlendirebilirsiniz,+JK-JK
Maltysen

@Maltysen Her ikisi de düzeltildi. Teşekkürler!
kirbyfan64sos

@orlp Hakkında hiçbir fikrim yoktu yve unuttum Z. Sabit; Teşekkürler!
kirbyfan64sos

6

Julia, 48 bayt

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

Bu, şimdiye kadar cevapların çoğu gibi yöntem 2 algoritmasını kullanır. Bir tamsayı girişi alan ve bir nx 2 dizisi döndüren lambda işlevi oluşturur. Bunu aramak için bir ad verin, örn f=n->....

Ungolfed + açıklaması:

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

Görselleştirmelerin görünüşünü gerçekten çok seviyorum, bu yüzden bir tane ekleyeceğim. Bunun sonucu f(1000).

Daire


5

Pyth, 22 bayt

C ++ cevabının bir portu. Başka bir 23 bayt çözümüm vardı (Şimdi 22!), Ancak optimizasyonlarla neredeyse @ kirbyfan64sos'un pyth cevabının bir kopyasıydı, bu yüzden kutunun dışında biraz düşünmek zorunda kaldım ve yaratıcı bir şekilde (ab) katlama operatörünü kullanın.

m,-Fdsdm,y*.nZOZ.tOZ4Q

Bunun, giriş operatörünün girişinden sonra bir hata nedeniyle şu anda çalışmadığını unutmayın reduce2. Çekme talebinde bulunuyorum.

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

Refence için bu aynı şekilde çalışan diğer çözümümdü: VQKy*.nZOZJ.tOZ4,+KJ-KJ


Sen :( ... kullanıcı adımı yanlış yazılmış
kirbyfan64sos

@ kirbyfan64sos derp. Üzgünüz;)
Maltysen

4

IDL, 65 bayt

Açıkçası bu, cevaplarını okumadan önce bağımsız olarak türetmiş olmama rağmen, @rcrmn ile aynı algoritma.

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

IDL'nin randomu işlevi, 2 19937 -1 dönemi olan Mersenne Twister'ı kullanıyor .

EDIT: Yukarıdaki görselleştirici üzerinden 1000 akor çalıştırdım, işte sonucun bir ekran görüntüsü:

IDL sertifikası


4

C ++ 11,214 bayt

#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<<';';}}

Bu , wikipedia sayfasından doğru algoritmanın doğrudan bir uygulamasıdır . Burada golfteki temel sorun, rastgele jeneratör sınıflarının sahip olduğu oh-freaking-long isimleridir. Ancak, iyi ol'rand'ın aksine, en azından düzgün bir şekilde eşittir.

Açıklama:

#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
Bu faktör M_PI_2şüpheli görünüyor. Bunun yerine 1 olması gerektiğini düşünüyorum.
anatolyg

Evet, tamamen doğru, şimdi düzelteceğiz! Çok teşekkürler!
rorlork

4

APL, 46 bayt

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

İlk APL programım! Elbette (APL genel anlayışım eksik olduğu için) büyük ölçüde geliştirilebilir, bu nedenle herhangi bir öneri harika olurdu. Bu, fgirdi olarak bir tamsayıyı alan, yöntem 2'yi kullanarak akor nokta çiftlerini hesaplayan ve her çifti bir satırsonu ile ayrılmış olarak basan bir işlev oluşturur .

Şunları yapabilirsiniz çevrimiçi denemek !

Açıklama:

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)
}

Not: Önceki 19 baytlık çözümüm (x + y, xy) yerine (x, y) döndürdüğü için geçersizdi. Üzüntü doludur.


3

Java, 114 bayt

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

Java'da temel uygulama. Lambda ifadesi olarak kullanın.

Örnek kullanım


Bir Mathyerde saklayarak boyutu küçültemez misiniz? Ya da başka birşey? (Ben bir Java programcısı değilim)
Ismael Miguel

@IsmaelMiguel Bu, fazladan 2 karaktere mal olur.
TheNumberOne

Üzgünüz: / MathGösterilen sayıyı azaltmaya çalışmak cazip geliyor . Meta, sorunu çözmek için başka bir kod oluşturmak için kod kullanma hakkında ne diyor?
Ismael Miguel

2
@IsmaelMiguel Bu adil bir oyundur, ancak metagolfing'de golf oynamaktan daha iyi olup olmadığınıza şaşıracağım.
Martin Ender

3

Yakut, 72 bayt

Burada ilk golf! Herkesle aynı kodu kullandım, umarım sorun olmaz

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

2

Java, 115123

Bu temelde diğerlerinin çoğu ile aynıdır, ancak bu delik için bir Java skoruna ihtiyacım var, işte burada:

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();}

1000 örnek akor, pastebin'de bulunabilir , işte bir çalışmanın ilk beşi:

8.147304676211474 3.772704020731153
8.201346559916786 3.4066194978900106
4.655131524088468 2.887965593766409
4.710707820868578 3.8493686706403984
3.3839198612642423 1.1604092552846672

1

CJam, 24 22 bayt

Diğer algoritmalara benzer şekilde, burada CJam'de bir sürüm var.

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

1000 girdisi aşağıdaki gibi bir dağıtım üretir:

resim açıklamasını buraya girin

Nasıl çalışır

Algoritma basitçe 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

Güncelleme : Martin sayesinde 2 bayt kaydedildi!

Burada deneyin


1

Python 3, 144 117 bayt

( lambdaişaretçi için Blckknght'a teşekkürler )

Diğerleriyle aynı yöntemi kullanarak:

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))]

Python belgelerinden:

Python, çekirdek jeneratör olarak Mersenne Twister'ı kullanıyor. 53 bit hassas şamandıralar üretir ve 2 19937 periyoduna sahiptir -1 .

Çıktı

>>> 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)]

Ve bunun gibi.

görüntüleme

görüntüleme


İşlev için bir lambda kullanırsanız ve bir liste kavrama (bir iç jeneratör ifadesi ile) döndürürseniz yaklaşık 20 bayt tasarruf edebilirsiniz:f=lambda n:[(x,x+2*m.acos(r()))for x in(2*m.pi*r()for _ in range(n))]
Blckknght

Ah, başlangıçta bir lambda'm vardı. Sanırım liste kavrayışlarını ikiye katlamayı düşünmedim. Teşekkürler! @Blckknght
Zach Gates,

İthalat ile uğraşarak
Triggernometry

1

Perl, 60

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

1

R, 60 56 53 49 bayt

@JayCe sayesinde ekstra 4 bayt ve bir işleve dönüştürülmesi.

Diğerleriyle aynı temel formülü kullanmak. R, Mersenne-Twister yöntemini varsayılan olarak kullanır, ancak diğerleri ayarlanabilir. Boşlukla ayrılmış bir liste çıkarır.

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

Çevrimiçi deneyin!


Merhaba Micky, bir işlev yaparak ve x tanımlayarak 4 bayt kaydedebilirsiniz .
JayCe

@JayCe çok daha iyi teşekkürler
MickyT

0

SmileBASIC, 62 bayt

INPUT N
FOR I=1TO N
X=PI()*2*RNDF()Y=ACOS(RNDF())?X+Y,X-Y
NEXT
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.