Sabit toplamlı rasgele sayılar


32

Görev bir yazmak için bir program veya bir fonksiyonu olduğu çıkışları n sabit toplamı [0,1] aralığı rasgele sayı s.

Giriş

n, n≥1, üretmek için rasgele sayıların sayısı

s, s>=0, s<=n, üretilecek sayıların toplamı

Çıktı

[0,1] aralığındakin tüm öğelerle birlikte kayan nokta sayılarının rasgele bir dizisi ve eşit olan tüm öğelerin toplamı, uygun olmayan herhangi bir şekilde çıkar. Tüm geçerli -tüpeler, kayan nokta sayısının sınırlamaları dahilinde eşit derecede muhtemel olmalıdır.sn

Bu, nboyutsal birim küp içindeki noktaların ve n-1içinden geçen (s/n, s/n, …, s/n)ve vektöre dik olan boyutsal hiper düzlemin kesişiminden eşit şekilde örneklemeye eşittir (1, 1, …, 1)(üç örnek için Şekil 1'deki kırmızı alana bakın).

N = 3 ve toplamları 0,75, 1,75 ve 2,75 olan örnekler

Şekil 1: N = 3 olan geçerli çıktı düzlemi ve toplamı 0,75, 1,75 ve 2,75

Örnekler

n=1, s=0.8 → [0.8]
n=3, s=3.0 → [1.0, 1.0, 1.0]
n=2, s=0.0 → [0.0, 0.0]
n=4, s=2.0 → [0.2509075946818119, 0.14887693388076845, 0.9449661625992032, 0.6552493088382167]
n=10, s=9.999999999999 → [0.9999999999999,0.9999999999999,0.9999999999999,0.9999999999999,0.9999999999999,0.9999999999999,0.9999999999999,0.9999999999999,0.9999999999999,0.9999999999999]

kurallar

  • Programınız, makinenizde en az n≤10bir kez geçerli bir s ile bitmelidir.
  • Arzu ederseniz, programınız üst uçta münhasır olabilir, yani s<nyarı açık aralıktan çıkış numaraları [0,1) (ikinci örneği kırarak)
  • Diliniz kayan nokta sayılarını desteklemiyorsa, çıkıĢı ondalık noktadan sonra en az on ondalık basamak ile düzenleyebilirsiniz.
  • Standart boşluklara izin verilmez ve standart giriş / çıkış yöntemlerine izin verilir.
  • Bu , yani bayt cinsinden ölçülen en kısa giriş kazanır.


Söylediğinizde This is equal to uniformly sampling from the intersection- sadece o kesişme köşesinden rastgele seçen bir program görebiliyorum. Bu geçerli olur mu?
JayCe

2
@KevinCruijssen Hayır, bu sadece için doğru s==0 or s==3. Tüm diğer değerleri siçin düzlem sıfır olmayan bir alana sahiptir ve o düzlemde bir noktaya rastgele seçmelisiniz.
user202729

3
Aralığın kapalı veya yarı kapalı olmasını gerektiren (açık yerine) teorik olarak gözlemlenemez bir gereksinimdir. Birçok rasgele sayı üreticisi çıktıyı (0,1) verir. Çıkış aralığının [0,1) olup olmadığını (0,1) nasıl test edersiniz? 0 değeri "asla" yine de gerçekleşir
Luis Mendo

2
Kodumuzda reddetme örneklemesi kullanılıyorsa ve bunun gibi test durumları için çok uzun sürüyorsa sorun olur s=2.99999999999, n=3mu? Diyelim ki, katları arasında rasgele gerçekler üretebilir miyiz 1e-9?
xnor

Yanıtlar:


1

Wolfram Dili (Mathematica) , 92 90 bayt

If[2#2>#,1-#0[#,#-#2],While[Max[v=Differences@Sort@Join[{0,#2},RandomReal[#2,#-1]]]>1];v]&

Çevrimiçi deneyin!

Golf edilmemiş kod:

R[n_, s_] := Module[{v},
  If[s <= n/2,             (* rejection sampling for s <= n/2:                        *)
    While[
      v = Differences[Sort[
            Join[{0},RandomReal[s,n-1],{s}]]];         (* trial randoms that sum to s *)
      Max[v] > 1           (* loop until good solution found                          *)
    ];
    v,                     (* return the good solution                                *)
    1 - R[n, n - s]]]      (* for s > n/2, invert the cube and rejection-sample       *)

İşte 55 baytta çalışan bir çözüm ama şimdilik (Mathematica sürüm 12) bununla sınırlı n=1,2,3çünkü RandomPointyüksek boyutlu hiper düzlemlerden puan çekmeyi reddediyor (TIO'nun 11.3 sürümünde de başarısız oluyor n=1). nGelecekte daha yüksek için işe yarayabilir :

RandomPoint[1&~Array~#~Hyperplane~#2,1,{0,1}&~Array~#]&

Çevrimiçi deneyin!

Golf edilmemiş kod:

R[n_, s_] :=
  RandomPoint[                           (* draw a random point from *)
    Hyperplane[ConstantArray[1, n], s],  (* the hyperplane where the sum of coordinates is s *)
    1,                                   (* draw only one point *)
    ConstantArray[{0, 1}, n]]            (* restrict each coordinate to [0,1] *)



4

Java 8, 194 188 196 237 236 bayt

n->s->{double r[]=new double[n+1],d[]=new double[n],t;int f=0,i=n,x=2*s>n?1:0;for(r[n]=s=x>0?n-s:s;f<1;){for(f=1;i-->1;)r[i]=Math.random()*s;for(java.util.Arrays.sort(r);i<n;d[i++]=x>0?1-t:t)f=(t=Math.abs(r[i]-r[i+1]))>1?0:f;}return d;}

Test baytlarının hızını 1'e yaklaşmak ve genel olarak algoritmayı düzeltmek için +49 byte (188 → 196 ve 196 → 237).

Çevrimiçi deneyin

Açıklama:

İçinde yaklaşımını kullanır bu StackOverflow'daki cevap öğelerden biri 1'den hala büyüktür sürece bir döngü içinde
eğer Ayrıca 2*s>n, siçine değişecek n-sve bir bayrak kullandığımız gerektiğini belirtmek için ayarlanır 1-diffyerine diffsonuç dizide ( @soktinpk ve @ l4m2 ucu için teşekkürler ).

n->s->{              // Method with integer & double parameters and Object return-type
  double r[]=new double[n+1]
                     //  Double-array of random values of size `n+1`
         d[]=new double[n],
                     //  Resulting double-array of size `n`
         t;          //  Temp double
  int f=0,           //  Integer-flag (every item below 1), starting at 0
      i=n,           //  Index-integer, starting at `n`
      x=             //  Integer-flag (average below 0.5), starting at:
        2*s>n?       //   If two times `s` is larger than `n`:
         1           //    Set this flag to 1
        :            //   Else:
         0;          //    Set this flag to 0
  for(r[n]=s=        //  Set both the last item of `r` and `s` to:
       x>0?          //   If the flag `x` is 1:
        n-s          //    Set both to `n-s`
       :             //   Else:
        s;           //    Set both to `s`
      f<1;){         //  Loop as long as flag `f` is still 0
    for(f=1;         //   Reset the flag `f` to 1
        i-->1;)      //   Inner loop `i` in range (n,1] (skipping the first item)
      r[i]=Math.random()*s;
                     //    Set the i'th item in `r` to a random value in the range [0,s)
    for(java.util.Arrays.sort(r);
                     //   Sort the array `r` from lowest to highest
        i<n;         //   Inner loop `i` in the range [1,n)
        ;d[i++]=     //     After every iteration: Set the i'th item in `d` to:
          x>0?       //      If the flag `x` is 1:
           1-t       //       Set it to `1-t`
          :          //      Else:
           t)        //       Set it to `t`
      f=(t=Math.abs( //    Set `t` to the absolute difference of:
            r[i]-r[i+1])) 
                     //     The i'th & (i+1)'th items in `r`
        >1?          //    And if `t` is larger than 1 (out of the [0,1] boundary)
         0           //     Set the flag `f` to 0
        :            //    Else:
         f;}         //     Leave the flag `f` unchanged
  return d;}         //  Return the array `d` as result

Zaman aşımıtest(10, 9.99);
l4m2

@ l4m2 Evet, test senaryosunu 10, 9.0düzeltmek için düzenledikten hemen sonra farkettim n=10, s=9.999999999999. Java’da düzgün bir şekilde rasgelelesini korurken hala bir düzeltme olup olmadığından emin değilim .. Bir süre düşünmek zorunda kalacağım. Şimdilik zaman aşımını belirtmek için düzenleyeceğim.
Kevin Cruijssen

Eğer n-s<1Arayabileceğin f(n,n-s)ve her numara ters çevirin 1/2(yani değiştirmek xile 1-xl4m2 gibi) yaptı. Bu, sayıların syakın olduğu sorunu çözebilir n.
soktinpk

@soktinpk Tahmininiz için teşekkürler. Aslında s+s>nbunun yerine n-s<1, ama diğer JavaScript cevaplarına baktığımda, gerçekten mantıklı geldi. Halen mevcut olan başka bir böcek de dahil olmak üzere her şey şimdi düzeltildi. Bayt biraz arttı, ama şimdi her şey çalışıyor. Buradan bayt-sayımı çalışacak. :)
Kevin Cruijssen

Genel bir kanıt bilmiyorum ama bu algoritmanın işe yaradığına inanıyorum, çünkü N boyutlu bir hiperküp N N boyutlu hiperpiramitlere bölünebilir.
Neil,


3

C ++ 11,284 267 bayt

Zacharý -17 bayt
C ++ rasgele kütüphane kullanır, standart çıktıya çıktı verir.

#include<iostream>
#include<random>
typedef float z;template<int N>void g(z s){z a[N],d=s/N;int i=N;for(;i;)a[--i]=d;std::uniform_real_distribution<z>u(.0,d<.5?d:1-d);std::default_random_engine e;for(;i<N;){z c=u(e);a[i]+=c;a[++i]-=c;}for(;i;)std::cout<<a[--i]<<' ';}

Aramak için, bunu yapmanız yeterlidir:

g<2>(0.0);

Burada şablon parametresi (burada, 2) N'dir ve gerçek parametre (burada, 0.0) S'dir.


Sanırım <z>ve arasındaki boşluğu kaldırabilirsinizu
Zacharý

Ben daha da aşağı var: typedef float z;template<int N>void g(z s){z a[N],d=s/N;int i=N;for(;i;)a[--i]=d;std::uniform_real_distribution<z>u(.0,d<.5?d:1-d);std::default_random_engine e;for(;i<N;){z c=u(e);a[i]+=c;a[++i]-=c;}for(;i;)std::cout<<a[--i]<<' ';}. Bir yeni satır, öğeler arasındaki ayırıcı olmak zorunda değildir
Zacharý

1
Kurtulmak Öner ddeğiştirerek tamamen d=s/Niçin s/=Nikinci döngü reworking öner for(z c;i<N;a[++i%N]-=c)a[i]+=c=u(e);yerine for(;i<N;){z c=u(e);a[i]+=c;a[++i]-=c;}(ilave not %Nprogramı hesapla yapmak için ilk sayı doğru)
Max Yekhlakov

2

Temiz , 221 201 bayt

Temiz, kod golf veya rasgele sayılar. İkisini seç.

import StdEnv,Math.Random,System._Unsafe,System.Time
g l n s#k=toReal n
|s/k>0.5=[s/k-e\\e<-g l n(k-s)]
#r=take n l
#r=[e*s/sum r\\e<-r]
|all((>)1.0)r=r=g(tl l)n s

g(genRandReal(toInt(accUnsafe time)))

Çevrimiçi deneyin!

Kısmi işlev değişmezi :: (Int Real -> [Real]). Sadece saniyede bir kez yeni sonuçlar üretecektir.
En az 10 ondalık basamağa kadar kesin.


2

R , 99 bayt ( gtoolspaket ile)

f=function(n,s){if(s>n/2)return(1-f(n,n-s))
while(any(T>=1)){T=gtools::rdirichlet(1,rep(1,n))*s}
T}

Çevrimiçi deneyin!

˜ A = { w 1 , kümesinden eşit olarak örnek almak istiyoruz .A~={w1,,wn:i,0<wi<1;wi=s}wisA={w1,,wn:i,0<wi<1s;wi=1}

s=1Dirichlet(1,1,,1) s1<1/ss

s>n/2


2

C, 132 127 125 118 110 107 bayt

@Ceilingcat sayesinde -2 bayt

i;f(s,n,o,d)float*o,s,d;{for(i=n;i;o[--i]=d=s/n);for(;i<n;o[++i%n]-=s)o[i]+=s=(d<.5?d:1-d)*rand()/(1<<31);}

Çevrimiçi deneyin!


Ne yazık ki, bu cevap zorluk şartnamesine uymuyor. Çıktı rasgele sayılarla sınırlı değildir [0,1]ve ortak dağılımları tekdüze değildir.
Nitrodon

@Nitrodon hey, çıkışın [0,1] ile sınırlı olmadığı bir girdi verir misiniz? Birkaç farklı örnek denedim ve amacı yanlış anlamadığım sürece hepsi doğru görünüyordu.
OverclockedSanic

RNG TIO üzerine devlet, ve tutma ile n=4, değerleri s=3.23ve s=0.89aralık çıkışlar dışında verir. Daha da önemlisi, dağılımına bağlı X-s/nolmalı s, ama buna bağlı değil.
Nitrodon

@ Nitrodon Oops, benim hatam. Yukarıdaki C ++ cevabından bazı kısımları dönüştürüyordum ve bir şey eklemeyi unuttum. Şimdi düzeltilmeli mi? Ayrıca bu süreçte birkaç bayt golf oynadı.
OverclockedSanic

1

Haskell , 122 217 208 bayt

import System.Random
r p=randomR p
(n#s)g|n<1=[]|(x,q)<-r(max 0$s-n+1,min 1 s)g=x:((n-1)#(s-x)$q)
g![]=[]
g!a|(i,q)<-r(0,length a-1)g=a!!i:q![x|(j,x)<-zip[0..]a,i/=j]
n%s=uncurry(!).(n#s<$>).split<$>newStdGen

Çevrimiçi deneyin!

Bazen kayan nokta hatası nedeniyle cevaplar biraz kapalıdır. Eğer bir sorun varsa, 1 byte pahasına düzeltebilirim. Bunun ne kadar düzgün olduğundan da emin değilim (gayet iyi olduğundan eminim ama bu tür şeylerde o kadar iyi değilim), bu yüzden algoritmamı tanımlayacağım.

Temel fikir, bir sayı üretmek, xonu çıkarmak sve ayırıp nelemanlar elimize geçirene kadar tekrarlamaktır . x1 veya sdaha üst bir sınırla (hangisi daha küçükse) ve bir alt sınır s-n+1veya 0'ı (hangisi daha büyükse) üretiyorum . Bu alt sınır oradadır, böylece bir sonraki yinelemede syine de eşit veya daha küçük olacaktır n(türetme: s-x<=n-1-> s<=n-1+x-> s-(n-1)<=x-> s-n+1<=x).

EDIT: Tekdüzelikteki kusuru gösterdiği için @ michi7x7 'e teşekkürler. Sanırım karışıklıkla düzelttim ama başka bir sorun olursa bana haber ver

EDIT2: Geliştirilmiş bayt sayısı ve sabit tip kısıtlaması


3
Tekdüze numunelerin zincirlenmesi asla tek tip bir dağılıma yol
açmaz

@ michi7x7 Amacınızı anlıyorum. Ya oluşturduktan sonra listenin sırasını karıştırırsam? Daha fazla istatistik dersi
almalıydım

Rakamlar çok tekdüze görünmüyor. Burada 8 sonuç> 0.99, 1 0.96 ve sonuncu 0.8. Bu göründüğü gibi değildir.
Stewie Griffin

@ user1472751 burada birkaç iyi cevap var: stackoverflow.com/q/8064629/6774250
michi7x7 19:01

1
Tekdüzelik hala bazı problemlere sahip, burada bakınız - üretilen çok fazla sıfır var (% 1000 500'den sıralanmış değerlerin grafiği)
Angs

1

Haskell , 188 bayt

import System.Random
import Data.List
n!s|s>n/2=map(1-)<$>n!(n-s)|1>0=(zipWith(-)=<<tail).sort.map(*s).(++[0,1::Double])<$>mapM(\a->randomIO)[2..n]>>= \a->if all(<=1)a then pure a else n!s

Ungolfed:

n!s
 |s>n/2       = map (1-) <$> n!(n-s)       --If total more than half the # of numbers, mirror calculation 
 |otherwise   = (zipWith(-)=<<tail)        --Calculate interval lengths between consecutive numbers
              . sort                       --Sort
              . map(*s)                    --Scale
              . (++[0,1::Double])          --Add endpoints
              <$> mapM(\a->randomIO)[2..n] --Calculate n-1 random numbers
              >>= \a->if all(<=1)a then pure a else n!s   --Retry if a number was too large

Çevrimiçi deneyin!

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.