Rand5 () işleviyle sağlanır. Bu işlev, 1 ile 5 arasında tam olarak rasgele (eşit dağılımlı) tamsayılar döndürür.
1 ile 7 arasında kusursuz rasgele tamsayılar üretmek için Rand5 () işlevini kullanan Rand7 () işlevini sağlayın.
Rand5 () işleviyle sağlanır. Bu işlev, 1 ile 5 arasında tam olarak rasgele (eşit dağılımlı) tamsayılar döndürür.
1 ile 7 arasında kusursuz rasgele tamsayılar üretmek için Rand5 () işlevini kullanan Rand7 () işlevini sağlayın.
Yanıtlar:
Java - 61 karakter
int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}
Doğrulama için test sürücüsü:
class Rand {
public static void main(String[] args) {
int[] nums = new int[7];
// get a lot of numbers
for(int i = 0; i < 10000000; i++) nums[rand7()-1]++;
// print the results
for(int i = 0; i < 7; i++) System.out.println((i+1) + ": " + nums[i]);
}
// just for rand5()
static java.util.Random r = new java.util.Random();
static int rand5() {
return r.nextInt(5)+1; // Random.nextInt(n) returns 0..n-1, so add 1
}
static int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}
}
Sonuçlar
C:\Documents and Settings\glowcoder\My Documents>java Rand
1: 1429828
2: 1429347
3: 1428328
4: 1426486
5: 1426784
6: 1429853
7: 1429374
C:\Documents and Settings\glowcoder\My Documents>
rand5
. Onları Maple'da basit matris cebiri kullanarak hesapladım, ancak isterseniz birkaç dakika içinde kalemle ve kağıtla yapabilirsiniz. Her neyse, Omar'ın birkaç gün önce başka bir cevaba yaptığı yorumda aynı rakamları (normalleştirici faktör sans) yayınladığı ortaya çıktı . (Ayrıca ps., Her yazıda yalnızca bir kullanıcıyı bildirebilirsiniz, ancak yazının yazarı her zaman her durumda bildirilir.)
sub rand7{($x=5*&rand5+&rand5-3)<24?int($x/3):&rand7}
Artı üçlü operatör VE özyinelemeyi kullanabiliyorum. En iyi gün!
Tamam, div yerine mod kullanıyorsanız 47 karakter:
sub rand7{($x=5*&rand5+&rand5)<27?$x%7+1:&rand7}
&
tabelayı 46 karaktere düşürmek için bırakabilirsiniz (mevcut sürümünüzü 48'e çıkartan alan dahil).
Ruby - 54 karakter (Dan McGrath çözümüne göre, döngü kullanılarak)
def rand7;x=8;while x>7 do x=rand5+5*rand5-5 end;x;end
Ruby - 45 karakter (özyineleme kullanarak aynı çözüm)
def rand7;x=rand5+5*rand5-5;x>7 ?rand7: x;end
(x=rand5+5*rand5-5)>7?
.
Common Lisp 70 karakterlerinde:
(defun rand7()(let((n(-(+(rand5)(* 5(rand5)))5)))(if(> n 7)(rand7)n)))
Parantez benden daha fazla yer kaplıyor.
(defun rand7()(setq n(-(+(rand5)(* 5(rand5)))5))(if(> n 7)(rand7)n))
(defun rand7()(if(>(setq n(-(+(rand5)(* 5(rand5)))5))7)(rand7)n))
C / c ++ 'da ret örneklemesini kullanarak
int rand7(){int x=8;while(x>7)x=rand5()+5*rand5()-5;return x;}
62 karakter
while(x>7)
, öyle ki, yalnızca geçerli aralıktaki sayılarla karşılanabilir.
Dan McGrath tarafından gönderilen cevaplardan PHP'ye çeviri.
function Rand7(){$x=8;while($x>7)$x=rand5()+5*rand5()-5;return $x;}
67 karakter.
R'de (istatistiksel hesaplama için oluşturulmuş bir dil), kasıtlı olarak aldatıcı bir çözüm:
# Construct a Rand5 function
Rand5 <- function() sample(seq(5),1)
# And the golf
Rand7=function(r=Rand5())sample(1:(r/r+6),1)
# Or (same character count)
Rand7=function(r=Rand5())sample.int(r/r+6,1)
# Or even shorter(thanks to @Spacedman)
Rand7=function()sample(7)[Rand5()]
Argümanların tembel değerlendirmesi sayesinde noktalı virgül ve parantezleri kaldırdım.
10 ^ 6 kopyadan fazla çıktı:
> test <- replicate(10^6,Rand7())
> table(test)
test
1 2 3 4 5 6 7
142987 142547 143133 142719 142897 142869 142848
library(ggplot2)
qplot(test)
Rand7=function(){r=Rand5();sample(7)[r]}
Rand7=function(){sample(7)[Rand5()]}
def rand7:Int={val r=5*(rand5-1)+rand5
if(r<8)r else rand7}
rand5'ten 2 giriş ile:
\ 1 2 3 4 5
1 1 2 3 4 5
2 6 7 8 ..
3 11 ..
4 ..
5
İlk 1'i 5 ile çarptım, ikincisini ekledim. Çoğu sonuç göz ardı edilir ve yeni bir hesaplamaya yol açar. Sonuç, 1-25 arasındaki değerlerin eşit bir dağılımı olmalıdır; bunlardan yalnızca ilk 7'sini seçiyorum. Modulo inşa eden ilk 21'i kabul edebilirdim, ancak bu daha uzun kodlara yol açacaktır.
başarısız olan tarihi kod, ancak çok açık bir şekilde değil. İşaretlediğiniz için Ilmari Karonen'e teşekkürler:
def rand7=(1 to 7).map(_=>rand5).sum%7+1
Yoshiteru Takeshita sayesinde, 'toplamı' çok kolaylaştıran bu ölçek-2.8.0-yaklaşımı için. Daha önce benim çözümüm:
def rand7=((0/:(1 to 7))((a,_)=>a+rand5-1))%7+1
rand5:
val rnd = util.Random
def rand5 = rnd.nextInt (5) + 1
def rand7=(1 to 7).map(_=>rand5).sum%7+1
int Rand4()
{
int r = Rand5();
return r > 4 ? Rand4() : r;
}
inline int Rand8()
{
return (Rand4() - 1) << 2 + Rand4();
}
int Rand7()
{
int r = Rand8();
return r > 7 ? Rand7() : r;
}
int Rand4(){int r=Rand5();return r>4?Rand4():r;}int Rand7(){int r=Rand4()-1<<2+Rand4();return r>7?Rand7():r;}
Dan McGrath tarafından yazılan cevaptan Javascript'e Çeviri.
function Rand7(){x=8;while(x>7)x=rand5()+5*rand5()-5;return x}
62 karakter
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}
biraz daha kısa: P
function Rand7(){for(x=0,i=1;i<8;x^=i*((k=Rand5())%2),i*=1+(k<5));return x?x:Rand7()}
Daha kısa cevap olduğunu biliyorum ama bu bulmacanın testini göstermek istedim . Sadece Clyde Lobo'nun Dan McGrath'ın ret örneklemesini kullanarak verdiği cevabın doğru olduğu ortaya çıktı (JS cevapları arasında).
int Rand7()
{
int r = Rand5();
int n = 5;
do {
r = (r - 1) * 5 + Rand5();
int m = n * 5 / 7 * 7;
if (r <= m) {
return r % 7 + 1;
}
r -= m;
n = n * 5 - m;
} while (1);
}
Sayı dağılımı (1000000 tam sayı):
142935 142751 142652 143299 142969 142691 142703
Her üretilen tamsayı için Rand5 () ortalama çağrı sayısı yaklaşık 2,2'dir (2 ila 10+).
1 2 3 4 5 6 7 8 9 10
0 840180 112222 44433 2212 886 0 60 6 1
Java'da (veya C / C ++ sanırım)
Alexandru tarafından üretilen formülü 65 karakterde kullanarak:
int rand7(){int x=rand5()*5+rand5()-6;return x>20?rand7():x/3+1;}
Dan McGrath tarafından üretilen formülün 60 karakter içerisinde kullanılması
int rand7(){int x=rand5()+5*rand5()-5;return x>7?rand7():x;}
Python'da yanlış olabilecek başka bir çözüm:
rand7 = lambda: sum(rand5() for i in range(7)) % 7 + 1
Bu çok basit görünüyor, ama denediğimde:
counter = [0] * 7
for i in range(100000):
counter[rand7()] += 1
Oldukça eşit bir dağılım elde ettim (hepsi 14000 ve 14500 arasında).
Tamam, şimdi birileri bu yazı için oy kullandı: Bu çözüm gerçekten doğru mu? Bunu daha çok insanların buraya eleştirmesini sağlamak için gönderdim. Eğer doğruysa golf versiyonum şöyle olurdu:
rand7=lambda:eval("+rand5()"*7)%7+1
37 karaktere çıkıyor.
Java, 65 karakter:
int rand7(){int r;do{r=rand5()+5*rand5()-5;}while(r>7);return r;}
def rand7():
while True:
n=5*(rand5()-1)+(rand5()-1)
if n<21:return n%7+1
ama tamamen doğru akıl yürütmeye dayalı burada .
sub rand7{1while($_=5*&rand5-rand5)>6;$_+1}
Bu, hakkında bir uyarı verir Ambiguous use of -rand5 resolved as -&rand5()
, ancak düzgün çalışır. &
İkinci rand5
aramaya da bir hazırlık yapılması, bir vuruş pahasına sabitlenir . (Buna karşılık, diğer &
de çıkarılabilir halinde rand5
bir ile tanımlanmıştır ()
prototip).
Ps. Aşağıdaki 46 karakterlik versiyon yaklaşık üç kat daha hızlı:
sub rand7{1while($_=5*&rand5-rand5)>20;$_%7+1}
int rand7(){int s;while((s=rand5()*5+rand5())<10);return(s%7+1);}
Önceki rutinden daha uzun, ancak bunun daha kısa sürede düzgün dağılmış sayıları döndürdüğünü düşünüyorum.
PostScript (46)
Bu, ikili kod kodlamasını kullanır, bu nedenle, burada bir hexdump:
00000000 2f 72 61 6e 64 37 7b 38 7b 92 38 37 92 61 7b 92 |/rand7{8{.87.a{.|
00000010 40 7d 69 66 92 75 32 7b 72 61 6e 64 35 7d 92 83 |@}if.u2{rand5}..|
00000020 35 92 6c 92 01 35 92 a9 7d 92 65 7d 92 33 |5.l..5..}.e}.3|
0000002e
Denemek için, indirebilirsiniz .
İşte kodlanmış ve yorumlanmış kod, test koduyla birlikte.
% This is the actual rand7 procedure.
/rand7{
8{ % potentialResult
% only if the random number is less than or equal to 7, we're done
dup 7 le{ % result
exit % result
}if % potentialResult
pop % -/-
2{rand5}repeat % randomNumber1 randomNumber2
5 mul add 5 sub % randomNumber1 + 5*randomNumber2 - 5 = potentialResult
}loop
}def
%Now, some testing code.
% For testing, we use the built-in rand operator;
% Doesn't really give a 100% even distribution as it returns numbers
% from 0 to 2^31-1, which is of course not divisible by 5.
/rand5 {
rand 5 mod 1 add
}def
% For testing, we initialize a dict that counts the number of times any number
% has been returned. Of course, we start the count at 0 for every number.
<<1 1 7{0}for>>begin
% Now we're calling the function quite a number of times
% and increment the counters accordingly.
1000000 {
rand7 dup load 1 add def
}repeat
% Print the results
currentdict{
2 array astore ==
}forall
int result = 0;
for (int i = 0; i++; i<7)
if (((rand(5) + rand(5)) % 2) //check if odd
result += 1;
return result + 1;
Rand7'yi tanımla:
rand7=function(n)sample(7,n,T)
R, istatistiksel analizler göz önünde bulundurularak yazıldığından, bu görev önemsizdir ve ben yerleşik işlevi sample
TRUE olarak değiştirerek kullanırım.
Örnek çıktı:
> rand7(20)
[1] 4 3 6 1 2 4 3 2 3 2 5 1 4 6 4 2 4 6 6 1
> rand7(20)
[1] 1 2 5 2 6 4 6 1 7 1 1 3 7 6 4 7 4 2 1 2
> rand7(20)
[1] 6 7 1 3 3 1 5 4 3 4 2 1 5 4 4 4 7 7 1 5
Buna ne dersin?
int Rand7()
{
return Rand5()+ Rand5()/2;
}
/
operatörü tamsayılı matematik yapar mı? Ondalık, kayan nokta veya tamsayılı matematik yaparsa sonuçlarınıza ne olur?
[2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]
. Tam olarak üniforma değil.
int m=0;int rand7(){return(m=m*5&-1>>>1|rand5())%7+1;}
Dağıtım testi:
[1000915, 999689, 999169, 998227, 1001653, 1000419, 999928]
Algoritma:
> Rakamlar artık karşılıklı olarak birbirleriyle ilişkilendirilmemektedir, ancak bireysel olarak mükemmel şekilde rasgeledir.
C / C ++ kodu çekirdek kodun sadece bir satırı var!
static unsigned int gi = 0;
int rand7()
{
return (((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1;
}
//call this seed before rand7
//maybe it's not best seed, if yo have any good idea tell me please
//and thanks JiminP again, he remind me to do this
void srand7()
{
int i, n = time(0);
for (i = 0; i < n % 7; i++)
rand7();
}
Srand7 (), rand7'nin çekirdeğidir, bu işlevi rand7'den önce çağırmalıdır, tıpkı C'deki rand'dan önceki srand gibi.
Bu çok iyi bir şey, çünkü sadece bir defa rand () diyor, döngü yok, fazladan hatıralar yok.
Açıklayayım: 5 ile bir tamsayı dizisi düşünün:
1st get one number from 1 2 3 4 5 by rand5
2nd get one number from 2 3 4 5 6
3rd get one number from 3 4 5 6 7
4th get one number from 4 5 6 7 1
5th get one number from 5 6 7 1 2
5th get one number from 6 7 1 2 3
7th get one number from 7 1 2 3 4
Böylece TABLO'yu aldık, 1-7'nin her biri 5 kez görünür ve 35 sayının hepsine sahiptir, bu nedenle her sayının olasılığı 5/35 = 1 / 7'dir. Ve bir dahaki sefere
8th get one number from 1 2 3 4 5
9th get one number from 2 3 4 5 6
......
Yeterli zaman sonra, 1-7 eşit dağılımını elde edebiliriz.
Böylece, 1-7'nin beş elemanını loop-sola kaydırma ile geri yüklemek için bir dizi tahsis edebilir ve her seferinde bir dizi rand5 ile bir sayı alabiliriz. Bunun yerine, yedi dizinin hepsini daha önce oluşturabilir ve dairesel olarak kullanabiliriz. Kod da basittir, bunu yapabilen birçok kısa kod vardır.
Ancak,% işleminin özelliklerini kullanabiliriz, bu nedenle 1-7 tablosu, (rand5 + i)% 7 ile eşdeğerdir, yani: a = rand ()% 5 + 1, C dilinde rand5'tir, b = gi ++ % 7, yukarıdaki tablodaki tüm permütasyonları üretir ve 0 - 6, 1 - 7 c = (a + b) yerine,% 7 + 1, tekdüze 1 - 7 oluşturur. Sonunda şu kodu aldık:
(((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1
Ancak, ilk görüşmede 6 ve 7'yi alamıyoruz, bu nedenle ilk resmi görüşme izinlerini geçersiz kılmak için bazıları C / C ++ 'da rand için srand gibi bir tohumya ihtiyacımız var.
İşte test için tam kod:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
static unsigned int gi = 0;
//a = rand() % 5 + 1 is rand5 in C language,
//b = gi++ % 7 generates all permutations,
//c = (a + b) % 7 + 1, generates 1 - 7 uniformly.
//Dont forget call srand7 before rand7
int rand7()
{
return (((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1;
}
//call this seed before rand7
//maybe it's not best seed, if yo have any good idea tell me please
//and thanks JiminP again, he remind me to do this
void srand7()
{
int i, n = time(0);
for (i = 0; i < n % 7; i++)
rand7();
}
void main(void)
{
unsigned int result[10] = {0};
int k;
srand((unsigned int)time(0)); //initialize the seed for rand
srand7() //initialize the rand7
for (k = 0; k < 100000; k++)
result[rand7() - 1]++;
for (k = 0; k < 7; k++)
printf("%d : %.05f\n", k + 1, (float)result[k]/100000);
}
6
ya 7
da arayarak kez ?
int main(){if(rand7()==6) printf("Hello, world!");}
, döngü kullanarak yaklaşıklık 'Merhaba, dünya!' 7 kez 1, ama kodunuz yok.