Rand5()からRand7()[クローズ]


29

関数Rand5()が提供されます。この関数は、1から5までの完全にランダムな(等分布)整数を返します。

Rand5()を使用して1から7までの完全にランダムな整数を生成する関数Rand7()を提供します。




1と5は含まれますか?すなわち、セット{1,2,3,4,5}からですか?
アーロンマクデイド

1
単一の勝者を決定する基準は何ですか?
小次郎

これを実感する瞬間は、実際には古い質問です。
nyuszika7h 14

回答:


11

Java-61文字

int rand7(){int s=0,c=7;while(c-->0)s+=rand5();return s%7+1;}

検証用のテストドライバー:

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

}

結果

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>

10
「オペレーターに行く」ための追加ポイント
スティーブP

文字を剃る?int rand7(){for(int s = 0、c = 7; c-> 0; s + = rand5()); return s%7 + 1;}
Ron

3
この答えは正しくありません。1から7の値を返すこの関数の確率は、それぞれ0.1430656、0.1430016、0.1428224、0.1426432、0.1426432、0.1428224、0.1430016です。はい、最小確率と最大確率の差は0.0005未満ですが、それでも質問は「完全にランダムな整数」を指定しました。
イルマリカロネン

@ilmariあなたは正しい-私はちょうどテストを実行し、分布が均一ではないようだ... ...私はその上で考えてみましょう
corsiKa

1
@userunknown:はい、投稿した確率は実際には近似値ではなく、完全にランダムであると仮定して正確です(0.1430656 = 11177/78125など)rand5。単純な行列代数を使用してMapleで計算しましたが、必要に応じて数分で鉛筆と紙を使って計算できます。とにかく、Omarはすでに数日前に別の回答へのコメントで同じ数字(正規化要因なし)を投稿していることがわかりました。(また、コメントごとに1人のユーザーにのみ@notifyできますが、投稿の作者には常に通知されます。)
Ilmari Karonen

7

Perl-47(52だった)文字

sub rand7{($x=5*&rand5+&rand5-3)<24?int($x/3):&rand7} 

さらに、三項演算子と再​​帰を使用できます。史上最高の日!

OK、divの代わりにmodを使用する場合は47文字:

sub rand7{($x=5*&rand5+&rand5)<27?$x%7+1:&rand7} 

近い... 30を27(= 6 + 21)に置き換えると、完全に均一な分布が得られます。ああ、最後の2つの&記号をドロップすると、46文字(現在のバージョンを48にするスペースを含む)になります。
イルマリカロネン

7

JavaScript、42

Rand7=f=_=>(x=Rand5()+Rand5()*5-5)>7?f():x

ボーナスES5のこと:

Rand7=eval.bind(0,'for(;x=Rand5()+Rand5()*5-5,x>7;);x')

6

Ruby-54文字(ループを使用したDan McGrathソリューションに基づく)

def rand7;x=8;while x>7 do x=rand5+5*rand5-5 end;x;end

Ruby-45文字(同じソリューション、再帰を使用)

def rand7;x=rand5+5*rand5-5;x>7 ?rand7: x;end

を使用して1文字短縮できます(x=rand5+5*rand5-5)>7?
ラースハウゲス


4

Common Lisp 70文字の場合:

(defun rand7()(let((n(-(+(rand5)(* 5(rand5)))5)))(if(> n 7)(rand7)n)))

括弧は、私が望むよりも多くのスペースを占有します。


いいね あなたはナ行うグローバル変数によって2つの以上の文字を絞り出すことができます:(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))
痛み博士

4

C / C ++で拒否サンプリングを使用

int rand7(){int x=8;while(x>7)x=rand5()+5*rand5()-5;return x;}

62文字。


@barrycarter:条件はwhile(x>7)ですので、有効な範囲内の数値によってのみ満たされます。
mellamokb

私の悪い。愚かなコメントを削除しました。
バリーカーター

@barryそして、あなたは別のものを残した。;)
Mateen Ulhaq

ここでの数学が拒否サンプリングに使用できる均一なランダム分布を生成する方法を理解するのに数分かかりました。
ダニエル


3

R、34文字

R(統計計算用に構築された言語)では、意図的に不正なソリューション:

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

引数の遅延評価のおかげで、セミコロンとブレースを削除しました。

10 ^ 6を超える複製の出力:

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

結果のヒストグラム


2
あなたが詐欺師になるつもりなら、あなたはあなたができる最高の詐欺師であるかもしれません:Rand7=function(){r=Rand5();sample(7)[r]}
Spacedman

あなたがそれをするつもりなら、なぜ中間ストレージに悩まされるのですか?Rand7=function(){sample(7)[Rand5()]}
ブライアンディグス

@BrianDiggs動作中のパス依存性.... :
アリB.フリードマン

3

スカラ座、47、40の 59文字:

def rand7:Int={val r=5*(rand5-1)+rand5
if(r<8)r else rand7}

rand5からの2つの入力:

\ 1 2 3 4 5 
1 1 2 3 4 5  
2 6 7 8 ..
3 11 ..
4 ..
5

最初の1に5を掛け、2番目を追加します。ほとんどの結果は無視され、新しい計算につながります。結果は、1〜25の値の均等な分布になるはずです。最初の7つの値のみを選択します。モジュロを構築して最初の21を受け入れることもできますが、これによりコードが長くなります。

失敗した歴史的なコードですが、それほど明白ではありません。指摘してくれたIlmari Karonenに感謝します。

def rand7=(1 to 7).map(_=>rand5).sum%7+1

'sum'を非常に簡単にしたこのscala-2.8.0-approachに対して、竹下義輝に感謝します。以前の私の解決策:

def rand7=((0/:(1 to 7))((a,_)=>a+rand5-1))%7+1

rand5:

val rnd = util.Random 
def rand5 = rnd.nextInt (5) + 1


ユーザー竹下義輝は、Scala 2.8.0以降で40文字に削減することを提案しましたdef rand7=(1 to 7).map(_=>rand5).sum%7+1
Peter Taylor

この解決策も正しくありません。glowcoderの回答へのコメントを参照してください。
イルマリカロネン

@IlmariKaronen:そのとおりです-私は解決策を作り直しました。
ユーザー不明

3

C ++

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

C ++(109)

ゴルフ

int Rand4(){int r=Rand5();return r>4?Rand4():r;}int Rand7(){int r=Rand4()-1<<2+Rand4();return r>7?Rand7():r;}

セミコロンはC ++のコード行を定義するため、これを「1つのライナー」と呼ぶことはできないと思います。
ピーターオルソン

@Peterまあ、もうワンライナーは必要ありません。
Mateen Ulhaq

1〜8の数値を返しました。
jimmy2301314

2

Dan McGrathによる回答からのJavaScriptへの翻訳。

function Rand7(){x=8;while(x>7)x=rand5()+5*rand5()-5;return x}

62文字


1
function Rand7(){for(x=8;x>7;x=rand5()+5*rand5()-5);return x}少し短いです:P
JiminP

2

JavaScript、85

function Rand7(){for(x=0,i=1;i<8;x^=i*((k=Rand5())%2),i*=1+(k<5));return x?x:Rand7()}

短い答えがあることは知っていますが、このパズルのテストを見せたかったのです。Dan McGrathの棄却サンプリングを使用したClyde Loboの回答のみが正しいことがわかります(JS回答間)。


2

С++

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

数分布(1000000整数):

142935 142751 142652 143299 142969 142691 142703

生成された整数ごとのRand5()の呼び出しの平均数は約2.2(2〜10+)です。

1 2      3      4     5    6   7 8  9 10
0 840180 112222 44433 2212 886 0 60 6 1

2

Java(またはC / C ++の場合)

  • Alexandruの生成式を65文字で使用します。

    int rand7(){int x=rand5()*5+rand5()-6;return x>20?rand7():x/3+1;}
    
  • Dan McGrathによる60文字の生成式を使用

    int rand7(){int x=rand5()+5*rand5()-5;return x>7?rand7():x;}
    

1

Clojure-58文字

(defn rand7[](#(if(<% 8)%(rand7))(+(rand5)(*(rand5)5)-5)))

1

Python、56 37文字

Pythonで間違っている可能性がある別のソリューション:

rand7 = lambda: sum(rand5() for i in range(7)) % 7 + 1

これは単純すぎるようですが、私が試してみると:

counter = [0] * 7
for i in range(100000):
     counter[rand7()] += 1

適度に均等な分布が得られます(すべて14000〜14500)。

さて、今、誰かがこの投稿に投票したとき:この解決策は本当に正しいですか?人々にそれを批判させるために、私はこれをここに投稿しました。まあ、それが正しい場合、私のゴルフバージョンは次のようになります。

rand7=lambda:eval("+rand5()"*7)%7+1

37文字になります。


あなたの解決策は正しくありません。公平な5面ダイスの7ロールに基づいて決定を下します。つまり、5 ^ 7(5の7乗)の確率の結果があります。これは7の倍数ではないため、7つの同等の結果を返すことはできません。私はあなたが返すものに簡単な公式があるとは思わない。計算をブルートフォースするか、より小さな数で手作業で実行することができます(3枚のコイン(H = 1、T = 2)を反転し、結果を合計します)。
ジル 'SO-悪である停止

1
生成された分布は均一ではありませんが、非常に近いです。各数値の確率の正確な割合は{1:11177、2:11172、3:11158、4:11144、5:11144、6:11158、 7:11172}
オマー



1

Perl、43文字、反復拒否サンプリング

sub rand7{1while($_=5*&rand5-rand5)>6;$_+1}

これによりについての警告が表示されますがAmbiguous use of -rand5 resolved as -&rand5()、正常に機能します。&また、2番目のrand5呼び出しの先頭に追加すると、1回のストロークで修正されます。(逆に、プロトタイプで定義されている場合、もう一方&も削除できます。) rand5()

追伸 次の46文字バージョンは、約3倍高速です。

sub rand7{1while($_=5*&rand5-rand5)>20;$_%7+1}

1

Java-66文字

int rand7(){int s;while((s=rand5()*5+rand5())<10);return(s%7+1);}

以前のルーチンよりも長いですが、これはより短時間で均一に分布した数値を返すと思います。


1

PostScript(46)

これはバイナリトークンエンコーディングを使用するため、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

試してみるには、ダウンロードすることもできます

これは、テスト用のコードとともに、コメント化されていないコードです。

% 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

-1
int result = 0;

for (int i = 0; i++; i<7)
    if (((rand(5) + rand(5)) % 2) //check if odd
        result += 1;

return result + 1;

2
これは均一な分布を与えません。10000回の反復にわたるrand(5)+ rand(5)の分布を見て、その理由を確認してください
gnibbler

結果は...あなたのコード内で1から8までの任意の数値を指定でき
オマール・

さらに、ニブラーが言ったように、分布は一様ではありません。(rand(5)+ rand(5))%2は0にバイアスされ、1を生成する12回ごとに0 13を生成します。つまり、確率は{0:13、1:12}に比例します。その表記法では、関数の確率は{1:62748517、2:405451956、3:1122790032、4:1727369280、5:1594494720、6:883104768、7:271724544、8:35831808}に比例します。より大きな数字)。または、6回実行するループを固定し、{1:4826809、2:26733096、3:61691760、4:75928320、5:52565760、6:19408896、7:2985984}
オマル

-1

R(30文字)

rand7を定義します。

rand7=function(n)sample(7,n,T)

Rは統計分析を念頭に置いて作成されたため、このタスクは簡単であり、組み込み関数を使用して、sample置換をTRUEに設定しています。

サンプル出力:

> 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

1
Rand5を使用する必要があると言っています。方法はわかりませんが、使用する必要があります...
Spacedman

@Spacedmanはい、明示的に無視しました。それは非参照による使用です。
アンドリー

-1

グルーヴィー

rand7={if(b==null)b=rand5();(b=(rand5()+b)%7+1)}

35,000回を超える反復の例:

[1:5030, 2:4909, 3:5017, 4:4942, 5:5118, 6:4956, 7:5028]

ステートフルであることは悪いですか?



-1

これはどう?

int Rand7()
{
    return Rand5()+ Rand5()/2;
}

つまり、その/演算子は整数演算を行いますか?10進数、浮動小数点、または整数演算を実行すると、結果はどうなりますか?
小次郎

整数除算を想定すると、この関数には次の分布があります[2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25]。正確に均一ではありません。
primo

プリモは正しい。乱数を追加すると、一般的に確率が中央の値に偏ります。
ニブラー

-1

Java-54

int m=0;int rand7(){return(m=m*5&-1>>>1|rand5())%7+1;}

配布テスト: [1000915, 999689, 999169, 998227, 1001653, 1000419, 999928]

アルゴリズム:

  • グローバル変数を保持する
  • 5を掛けると、最下位で5つの場所が空く
  • 符号ビットを切り捨てて正にします(符号なしの数値がサポートされている場合は不要です)
  • モジュロ7が答えです

>数値は相互に無相関ではなくなり、個別に完全にランダムになりました。


-1

ルビー(43バイト)

def rand7;(0..7).reduce{|i|i+rand5}%7+1;end

Rubyに移植されたcemper93のソリューションは3バイト短くなります;)(34バイト)

def rand7;eval("+rand5"*7)%7+1;end

-3

C / C ++コードのコアコードには1行しかありません!

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のシードです。Cでrandの前にsrandを呼び出すように、rand7の前にこの関数を呼び出す必要があります。

これは非常に良い方法です。rand()を1回だけ呼び出し、ループ処理も余分なメモリも消費しないためです。

説明しましょう:サイズが5の整数配列を考えてみましょう:

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

TABLEを取得し、1〜7のそれぞれが5回出現し、35個すべての数字があるため、各数字の確率は5/35 = 1/7です。そして次回は

8th get one number from 1 2 3 4 5
9th get one number from 2 3 4 5 6
......

十分な時間の後、1-7の均一な分布を得ることができます。

したがって、ループ左シフトによって1〜7の5つの要素を復元する配列を割り当て、rand5によって毎回配列から1つの数値を取得できます。代わりに、前に7つの配列すべてを生成し、それらを循環的に使用できます。コードもシンプルで、多くの短いコードでこれを行うことができます。

ただし、%演算のプロパティを使用できるため、表1-7の行は(rand5 + i)%7と同等です。つまり、C言語ではa = rand()%5 + 1はrand5、b = gi ++です。 %7は上の表のすべての順列を生成し、0-6は1-7を置き換えますc =(a + b)%7 + 1は、1-7を均一に生成します。最後に、このコードを得ました:

(((rand() % 5 + 1) + (gi++ % 7)) % 7) + 1 

ただし、最初の呼び出しで6と7を取得できないため、最初の正式な呼び出しの順列を乱すために、C / C ++のrand for randのようなシードが必要です。

テストの完全なコードは次のとおりです。

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

これは「テスト」に「合格」しますが、これが良いランダム関数であることを意味するものではありません。取得する67一度呼び出すことで取得できますか?
JiminP

しかし、良い種類と悪い種類の近似があります。そして、このコードは悪いです-それ一度だけ呼び出されたときに均一な分布を与えないためです。のようなものを書いた場合int main(){if(rand7()==6) printf("Hello, world!");}、ループを使用した近似は 'Hello、world!'を出力します。7回に1回ですが、コードはそうではありません。
JiminP

ありがとう@JiminP!初めて6,7に適しています。C / C ++のsrandのようなシードrand7を呼び出す前に、配列を乱すシードが必要です。コードを修正し、ありがとうございます!!!
ショーン

hm .... srand10は機能しません。最後の3つの数字は、10、20、30 ...の位置では取得できません。@JiminPを申し訳ありませんが、それを修正する方法は?これは希望に満ちた方法だと思います。
ショーン

2
この関数の異なる呼び出しは、互いに独立していません。ここでの仕様ではこれは必要ありませんが、通常は乱数ジェネレーターの仕様です。そうしないと、あなたはランダムな均一な番号を最初に返す、と言うと、将来的には(前回+ 1)%7 ...ちょうどリターンを呼び出すことができ
オマール・
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.