最初は「-3~3の整数を得る」という仕様でよく、こんな感じでした。※本当の最初のコードはコメントアウトの物でしたが、ごくまれに-4が出るというバグがあるので修正しました。
javascript
1var v = (Math.floor(Math.random() * 7) - 3); 2//var v = (Math.ceil(Math.random() * 7) - 4);
ただ、0は除外しようと思いここからコードを変更しようと思ったのですが、シンプルな方法が思いつきませんでした。
一応、以下の2案は思いついたのですが、
- 候補の値を配列で持つ
- 「1, 2, 3」をランダムで得た後、「+ or -」をランダムで得てかける
あまりエレガントではないと思い、採用を躊躇しています。
この程度の規則なら数学的なテクニックを駆使して導き出るのではないかと思っています。
「-3, -2, -1, 1, 2, 3」の6つの整数をランダムで得る「いい」方法、
これについて教えてください。よろしくお願いします。
補足追記
2017/02/04 12:00頃、質問内容を「数学的」から「いい方法」に変更しました。
私がもともと考えていた「数学的な方法」とは以下の条件です。
- Math関数と算術演算子・ビット演算子だけを使う
- Math.randomの使用は1回のみ
- 条件分岐・配列(あるいは配列に類するもの)を使わない
- 出来れば、関数・変数を使わない、1行で書けるコード
ただ、「数学的な方法」にこだわりすぎたり、他の選択肢を捨ててしまうのも違うなと思い、「いい方法」に変更しました。
最初に考えていた「数学的な方法」を満たす回答も引き続き歓迎しますが、同時にシンプルな方法や、意外な方法もお待ちしています。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答21件
0
0-5をマッピングする式だけ書きますが
(x+4)%7-3
スマホからなので同じ回答見落としていたらごめんなさい。
追記。ちゃんとJSで書きます。
return (Math.floor(Math.random() * 6) + 4) % 7 - 3
投稿2017/02/09 23:55
編集2017/02/10 03:41総合スコア5570
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/10 00:55
退会済みユーザー
2017/02/10 01:36 編集
2017/02/10 01:32
2017/02/10 01:39
2017/02/10 02:12
2017/02/10 03:44
2017/02/11 01:03
0
「数学的」という言葉の定義が不明なので確かな回答はできませんが、
javascript
1var v = Math.floor(Math.random() * 6); 2v -= (v < 3) ? 3 : 2;
または
javascript
1const map = [-3, -2, -1, 1, 2, 3]; 2var v = map[Math.floor(Math.random() * 6)];
ちなみに、
javascript
1var v = (Math.ceil(Math.random() * 7) - 4);
と書くと、v は -4, -3, -2, -1, 0, 1, 2, 3 のいずれかの整数となります。
なぜなら、0 <= Math.random() < 1
である(※)ため、Math.random() が 0 を返したとき、
Math.ceil(0 * 7) - 4 == 0 - 4 == -4;
となるからです。
※ https://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2.14
Returns a Number value with positive sign, greater than or equal to 0 but less than 1
正の符号で、0 以上 1 未満の数を返します
投稿2017/02/03 00:42
総合スコア4791
0
2ビットと符号ビットで足りることに着目し、000
と100
を排除すればいいことに気づきました。
1~6をランダムに生成し、下位2ビットを残し、3桁目ビットで全ビットそろえてXOR
取ってます。
javascript
1var v = ( x => 2 ( x & 0b11 ) ^ ( 0- ( ( x & 0b100 ) >> 2 ) ) 3)( Math.random() * 6 + 1 )
追記
think49さんの「汎用性が高いコードがエレガント」という言葉と、raccyさんのカリー化に刺激を受けまして、一般化してみました。
javascript
1var f = n => 2 x => ( x => 3 x + (( x & 0b1000000000000000000000000000000) >> 30) - 0b1000000000000000000000000000000 4 )( Math.floor( Math.random() * 2 * n + ( 0b1000000000000000000000000000000 - n ) ) ); 5var v = f(3)();
f(n)
は[n, n-1, ... 1,-1, ... -(n-1), -n]の乱数を返す関数を返します。たぶん。
ただし、javascriptで扱える整数に上限があるため、nには上限があります。おそらく。
投稿2017/02/03 12:24
編集2017/02/04 11:54総合スコア36928
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/04 06:55
2017/02/04 11:52
0
ベストアンサー
var v = (Math.floor(Math.random() * 3) + 1) * ((Math.floor(Math.random() * 2) + 1) * 2 - 3);
random の仕様がわかっていませんでした。例題を見て 0 は出ないと思い込みました。書き直しました。
もう一つ。
var a = Math.floor(Math.random() * 6); var v = a - 3 + Math.floor(a / 3);
もう一つ。
var v = Math.round((Math.floor(Math.random() * 6) - 2.5) * 1.1);
追記
三番目のものについて修正しました。
また、検証しました。
以下のコードにて
<!DOCTYPE html> <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script> $(function(){ var data = {}; for (var i = 0; i < 1000; i++) { var v = Math.round((Math.floor(Math.random() * 6) - 2.5) * 1.1); if (!(v in data)) { data[v] = 0; } data[v]++; } for (var key in data) { $('table').append(`<tr><th>${key}</th><td>${data[key]}</td></tr>`); } }); </script> </head> <body> <table> <tr> <th>数値</th><td>出現回数</td> </tr> </table> </body> </html>
次の結果となりました。
数値 出現回数
1 139
2 179
3 167
-1 177
-2 162
-3 176
0 は発生せず、仕様を満たしているようです。
投稿2017/02/03 00:26
編集2017/02/05 12:36総合スコア28669
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/03 00:37
2017/02/03 00:55 編集
2017/02/03 00:59 編集
2017/02/04 02:19
2017/02/04 02:25
2017/02/04 11:18
2017/02/05 00:42
2017/02/05 02:06
2017/02/05 02:20
2017/02/05 12:36
0
「-3, -2, -1, 1, 2, 3」を配列として捉えて、ランダムに選ぶのは、ワリとやる手だと思います。
シンプルだと思いますが。
数学的な方法って、どんなものをイメージしていますか?
補足
シンプルな方法ということで、乱数の元は組み込まれた関数を使用するものとします。
すると乱数は連続する数値の範囲を指定することになります。
その前提で考えると、「-3, -2, -1, 1, 2, 3」を連続した数値に直すか、連続した順番で捉えるかの2択になるかと。
前者は多段な処理を行わなければならないのであまりシンプルな発想ではないと思います。
シンプルさで言えば、後者の配列として捉える方法が適解かと。
重要な追記
途中から、識者が指摘を諦めてますがw
Math.random() の取る範囲が、0以上1未満なので、一様性を確保しようとするとMath.floor()と組み合わせるのがセオリーなんですね。今回は勉強になりました。
Math.ceil() 使っているヒトォー、0 問題クリアできていませんよぉー。
0を有効数字として扱うと、一様ではなくなるので組み合わせとしては最悪ですね。
Math.round() はコツがいりますね。発生した乱数を0.5ずらしてやらなければ一様にならない。
投稿2017/02/02 23:55
編集2017/02/04 00:55退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/02/03 00:37
2017/02/03 03:25 編集
退会済みユーザー
2017/02/03 03:52
2017/02/03 13:39 編集
退会済みユーザー
2017/02/03 14:16
2017/02/03 14:27
退会済みユーザー
2017/02/03 14:46
退会済みユーザー
2017/02/04 00:56
2017/02/04 02:01
退会済みユーザー
2017/02/04 02:35
2017/02/04 02:52
退会済みユーザー
2017/02/04 03:17
2017/02/04 04:19
退会済みユーザー
2017/02/04 04:52
2017/02/04 07:25
2017/02/04 10:06 編集
0
node
1$ node 2> function f(x) { return (x - 2.5) + Math.sign(x - 2.5) * 0.5; } 3undefined 4> function rand() { return Math.floor(Math.random() * 6); } 5undefined 6 7> [f(0), f(1), f(2), f(3), f(4), f(5)] 8[ -3, -2, -1, 1, 2, 3 ] 9 10> [f(rand()), f(rand()), f(rand()), f(rand())] 11[ 3, -2, 1, -1 ] 12> [f(rand()), f(rand()), f(rand()), f(rand())] 13[ -3, 3, 1, 3 ] 14> [f(rand()), f(rand()), f(rand()), f(rand())] 15[ -2, -2, -2, 1 ] 16> [f(rand()), f(rand()), f(rand()), f(rand())] 17[ -1, 3, -3, 1 ] 18> [f(rand()), f(rand()), f(rand()), f(rand())]
数学的には、x に対する f(x) が次のようになる関数 f を作ればよいことになります。
x: 0 1 2 3 4 5
f(x): -3 -2 -1 1 2 3
f(x) = (x - 2.5) + sign(x - 2.5) * 0.5 は、その 1 つの例になります。
ここで sign(x)は
x < 0 なら -1 を返す
0 < x なら 1 を返す
ような関数とします。
f を javascript (node.js) で書き、動作を試してみたのが↑です。
追記:
数学的なことをだらだらと述べます。
f(n) = m が n 個与えられたとき、それを満たす x の多項式はいくつも存在します。
一般的には n 個に対しては (n - 1) 次多項式で、それが可能です。
(2点なら、1次式で可能になる)
参考
- ニュートン補完 https://ja.wikipedia.org/wiki/%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%88%E3%83%B3%E8%A3%9C%E9%96%93
ここでの質問の場合は、6つの f(x) = m があたえられているので 5 次多項式の答えが存在するはずです。
しかし、ここでの質問のケースでは、 ほとんど直線であり、その直線を途中でちょっとずらすだけで条件をみたすことができます。
ずらす操作を if での条件分岐で記載することも可能です。
普通の多項式はすべてなだらかなグラフになりますが、なだらかにならない式として
|x| とか sgn(x) とか floor(x) とか ディリクレ関数 ... があります。
ここでは、 sgn(x) (x が正なら 1, 負なら -1, 0 なら 0 を返す) を利用することで、直線をずらす処理を数式で
表現してみたのです。
floor(x) をつかっても、直線をずらすことを表現できる気もします。
投稿2017/02/03 16:36
編集2017/02/04 05:38総合スコア22324
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/04 03:15
2017/02/04 07:21
2017/02/04 11:38
0
整数の商と剰余を使えばできますね。
出来れば、関数・変数を使わない、1行で書けるコード
には反しますが...
JavaScript
1function randomValue() { 2 return (function(x) { 3 return (x % 3 + 1) * (Math.floor(x / 3) * 2 - 1); 4 })(Math.floor(Math.random() * 6)); 5}
もうひとつ、全然エレガントではない方法。
結局、[0, 1, 2, 3, 4, 5] => [-3, -2, -1, 1, 2, 3] の単射が欲しいわけです。
長さnの数値配列は、n-1次多項式で表現できます。
5次式だと大変なので、[0, 1, 2, 3] => [-2, -1, 1, 2] で考えます。
(x, y) = (0, -2), (1, -1), (2, 1), (3, 2)
の4点を通る3次関数 y = ax^3 + bx^2 + cx + d の係数は、線形代数だけで求められ、
y = -1/3x^3 + 3/2x^2 - 1/6x - 2
となります。
JavaScript
1function randomPoly() { 2 return (function(x) { 3 return -1/3*x*x*x + 3/2*x*x - 1/6*x - 2; 4 })(Math.floor(Math.random() * 4)); 5}
いかがでしょうか?
投稿2017/02/04 19:14
編集2017/02/04 19:40総合スコア14
0
無理やりやってみました。
引き直しなど条件分岐は行わず、
[0,5]の整数の一様分布に対してちゃんと均等な出現確率になるようになっています(多分)
javascript
1function f(t){ 2 return Math.ceil(Math.abs(t-2.5))*Math.sign(t-2.5) 3} 4 5function g(){ 6 r = Math.floor(Math.random() * 6) 7 return f(r) 8} 9 10console.log([0,1,2,3,4,5].map(f)) 11 12histogram=[0,0,0,0,0,0,0] 13for(i=0;i<1000;i++){ 14 histogram[g()+3] ++ 15} 16console.log(histogram)
投稿2017/02/03 00:20
編集2017/02/03 00:32総合スコア13551
0
数学的なテクニックっぽい計算式
javascript
1var v = Math.round(Math.sin((Math.floor(Math.random() * 6) - 2.5) * 36 * Math.PI / 180) * 3);
エレガントにはほど遠いですね。パフォーマンスも最悪だと思います。
配列を使うのが一番シンプルで無難かと思います。
投稿2017/02/03 01:54
総合スコア5944
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/04 02:33
2017/02/04 02:43
0
【条件】
- 乱数生成は1度のみ行う。
- 任意の整数
n
に対して、-n
,-n+1
, ...-2
,-1
,1
,2
, ...n-1
,n
の計n*2個の整数の内一つを返す。ランダム性は1.で生成した乱数を用いること。ただし、n
は1
以上2**52-1
以下とする。(2**52
以上の場合は2*n
がNumber.MAX_SAFE_INTEGER
を越えるため)
【考察】
Math.random()
[0,1)の乱数
Math.random()*2*n
[0,2n)の乱数
Math.floor(Math.random()*2*n)
0, 1, 2, ... 2n-2, 2n-1 の乱数
それぞれn
でわると前半は0
以上1
未満、後半は1
以上2
未満となる。
fn = i=>Math.floor(i/n)
0, 1, ... n-1, n ... 2n-2, 2n-1 => 0, 0, ... 0, 1, ... 1, 1
そこで次のような関数を考える。
gn = x=>x+1-(2*n+1)*fn(x)
0, 1, ... n-1, n ... 2n-2, 2n-1 => 1, 2, ..., n, -n, -n+1, .. -2, -1
よって
gn(Math.floor(Math.random()*2*n))
(x=>x+1-(2*n+1)*fn(x))(Math.floor(Math.random()*2*n))
(x=>x+1-(2*n+1)*(i=>Math.floor(i/n))(x))(Math.floor(Math.random()*2*n))
関数の中の関数は、引数に副作用が無いため、そのまま評価できるので
(x=>x+1-(2*n+1)*Math.floor(x/n))(Math.floor(Math.random()*2*n))
副作用があるMath.random()
を引数にとるように式を変形すると
(x=>Math.floor(2*n*x)+1-(2*n+1)*Math.floor(2*x))(Math.random())
1, 2, 3, ... n-1, n, -n, -n+1, ... -2, -1 の乱数
求めるのはn=3の時なので、
(x=>Math.floor(6*x)+1-7*Math.floor(2*x))(Math.random())
1, 2, 3, -3, -2, -1 の乱数
【解】
JavaScript
1let v = (x => Math.floor(6 * x) + 1 - 7 * Math.floor(2 * x))(Math.random());
数学っぽく考えたつもりですが、Math.random()
に副作用があるのでまったく数学っぽくない時点でなんとも言えないです。
【別解】
[0,1) => -n, -n+1, ... -2, -1, 1, 2, ... n-1, n
となる写像関数を直接考える。
- 2倍すれば[0,2)となるため、[0,1), [1,2)に分離でき、floorをとれば0, 1になる。
- -1を底、1.の値を冪指数とする冪を求めると、1, -1になる。
- 2n倍すれば[0,2n)となるため、[0,1), [1,2), ... [n-1, n), [n, n+1), ... [2n-2,2n-1), [2n-1,2n)に分離でき、floorをとれば0, 1, ... n-1, n, ... 2n-2, 2n-1となる。
このうちの前半は1.の0(2.の1)に、後半は1.の1(2.の-1)に相当する。
4. さらにnでの余りを求めると0, 1, ... n-1, 0, ... n-2, n-1と前半と後半が同じである。
5. さらに1足せば1, 2, ... n, 1, ... n-1, nとなる。
6. 2.と5.を組み合わせれば、目的の写像が得られる。
f(n)(x) = (-1)^[2x]*([2nx]%n+1)
※ fはカリー化されている。^ ... 冪乗。[z] ... ガウス記号、床関数。% ... 剰余。
これをJavaScriptで表すと下記になる。
JavaScript
1const f = n => x => (-1)**Math.floor(2 * x) * (Math.floor(2 * n * x) % n + 1)
写像関数が得られたので、n=3の時にxが[0,1)分布の乱数を与えることで答えは
JavaScript
1let v = (n => x => (-1)**Math.floor(2 * x) * (Math.floor(2 * n * x) % n + 1))(3)(Math.random());
となる。
【別解2】
※ 途中の演算でMath.MAX_SAFE_INTEGER
を越える場合があるため修正。
Math.floorを一回だけにする方法を考える。他にも演算はなるべく1回とする。
2n倍したものにfloorをとると0, 1, ... 2n-2, 2n-1になる。
これを2を除数とした商と剰余を考えると、下記になる。
商: 0, 0, 1, 1, ... 2n-2, 2n-2, 2n-1, 2n-1
剰余: 0, 1, 0, 1, ... 0, 1, 0, 1
つまり、剰余部分は-1を底にしてその値を冪指数にした冪を求めれば
剰余: 0, 1, 0, 1, ... 0, 1, 0, 1 => 1, -1, 1, -1 ... 1, -1, 1, -1
が得られるため、後は商に1足した物と掛ければ、
1, -1, 2, -2, ... 2n-1, -2n+1, 2n, -2n
が得られる。
JavaScriptにすると次のような関数になる。
JavaScript
1// q 商、r 剰余 2const g = r => q => (-1)**r * (q + 1);
JavaScriptには商を直接求める演算子や関数がないため剰余から求める関数を考える。
JavaScript
1// d 被除数、m 除数 2const h = d => m => r => (d - r) / m;
除数は2で固定であるため、これを用いると次のようになり、展開しながら変形していく。
JavaScript
1const f = x => g(x % 2)(h(x)(2)(x % 2)); 2// `x % 2`は冗長のためさらに書き替える。 3const f = x => (r => g(r)(h(x)(2)(r)))(x % 2); 4// 関数を展開する。 5const f = x => (r_ => (r => q => (-1)**r * (q + 1))(r)((d => m => r => (d - r) / m)(x)(2)(r_)))(x % 2); 6// rはr_と同じ、xとdは同じであり、mは2固定で冗長のためまとめる。 7const f = x => (r => (q => (-1)**r * (q + 1))((m => (x - r) / 2)()))(x % 2); 8// 固定の所は評価をしてしまって。qもなくす。 9const f = x => (r => ((-1)**r * ((x - r) / 2 + 1)))(x % 2);
これに最初の2nを掛けて床関数で整数化したものを与えると[0,1)を均等に配分できる。
JavaScript
1const f_ = n => y => (x => (r => ((-1)**r * ((x - r) / 2 + 1)))(x % 2))(Math.floor(2 * n * y));
n=3のときのため、最終的に次のようになる。
JavaScript
1let val = (n => y => (x => (r => ((-1)**r * ((x - r) / 2 + 1)))(x % 2))(Math.floor(2 * n * y)))(3)(Math.random());
【別解3】
-1は奇数乗か偶数乗かだけで切り替わることに気付いた。
JavaScript
1let val = (x => ((-1)**x * ((x - x % 2) / 2 + 1)))(Math.floor(6 * Math.random()));
IE等の古いブラウザ用に書き直すと
JavaScript
1var val = function (x) {return Math.pow(-1, x) * ((x - x % 2) / 2 + 1);}(Math.floor(6 * Math.random()));
投稿2017/02/03 13:55
編集2017/02/04 13:06総合スコア21737
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/05 01:41 編集
2017/02/05 02:00
0
数学的にエレガントとは
「miu_ras さんがエレガントと思うコードの定義」が不明なので、私がエレガントと思うコードの定義を書きます。
(1) [-3,-2,-1,0,1,2,3] からランダムに値を得てから 0 を例外処理するコードはエレガントではない
0 を除外するコードは2種類考えられます。
- 0 が返された場合、1 を返す
- 0 が返された場合、もう一度、[-3,-2,-1,0,1,2,3] からランダムに値を得る(0 が返されなくなるまで繰り返す)
前者は 1 が返される確率が上がる為、エレガントではありません。
後者は 0 が返された場合の処理コストが上がる為、エレガントではありません。
(2) 配列からランダムに値を得る方法はエレガントではない
[-3,-2,-1,0,1,2,3] からランダムに値を得る方法はシンプルですが、配列を生成するコストがかかるのでエレガントではありません。
配列からランダムに値を得るコード
[1,2,3]
を元に [-3,-2,-1,1,2,3]
を生成するコード。
JavaScript
1function createIntArray1 (minInt, maxInt) { 2 var array = [...Array(maxInt + 1).keys()].slice(minInt); 3 4 return array.slice().reverse().map(value => value * -1).concat(array); 5} 6 7function createRandomInt1 (minInt, maxInt) { 8 var array = [...Array(maxInt + 1).keys()].slice(minInt); 9 10 array = array.slice().reverse().map(value => value * -1).concat(array); 11 return array[Math.floor(Math.random() * array.length)]; 12} 13 14console.log(JSON.stringify(createIntArray1(1, 3))); // [-3,-2,-1,1,2,3] 15console.log(createRandomInt1(1, 3)); 16console.log(createRandomInt1(1, 3)); 17console.log(createRandomInt1(1, 3)); 18console.log(createRandomInt1(1, 3)); 19console.log(createRandomInt1(1, 3)); 20console.log(createRandomInt1(1, 3)); 21console.log(createRandomInt1(1, 3)); 22console.log(createRandomInt1(1, 3)); 23console.log(createRandomInt1(1, 3)); 24console.log(createRandomInt1(1, 3));
[0,1,2,3,4,5,6,7]
を元に [-3,-2,-1,1,2,3]
を生成するコード。
JavaScript
1function createIntArray2 (minInt, maxInt) { 2 var halfLength = maxInt - minInt + 1, 3 array = [...Array(halfLength * 2 + 1).keys()].map(value => value - halfLength); 4 5 return array.splice(halfLength, 1), array; 6} 7 8function createRandomInt2 (minInt, maxInt) { 9 var halfLength = maxInt - minInt + 1, 10 array = [...Array(halfLength * 2 + 1).keys()].map(value => value - halfLength); 11 12 return array.splice(halfLength, 1), array[Math.floor(Math.random() * array.length)]; 13} 14 15console.log(JSON.stringify(createIntArray2(1, 3))); // [-3,-2,-1,1,2,3] 16console.log(createRandomInt2(1, 3)); 17console.log(createRandomInt2(1, 3)); 18console.log(createRandomInt2(1, 3)); 19console.log(createRandomInt2(1, 3)); 20console.log(createRandomInt2(1, 3)); 21console.log(createRandomInt2(1, 3)); 22console.log(createRandomInt2(1, 3)); 23console.log(createRandomInt2(1, 3)); 24console.log(createRandomInt2(1, 3)); 25console.log(createRandomInt2(1, 3));
数学的にエレガントなアルゴリズム
下記アルゴリズムは miu_ras さんが質問文中で「エレガントではない」としていますが、数学的に解決する方法の一つだと私は思います。
Math.random()
で 1,2,3 の乱数を得るMath.random()
で -1,1 の乱数を得る-
- と 2. の積を求める
数学的にエレガントなコード
私が考える数学的にエレガントなコードは「Math.xxxx
メソッド、算術演算子だけで完結するコード」です。
JavaScript
1function createRandomInt (minInt, maxInt) { 2 return (Math.round(Math.random()) * 2 - 1) * (Math.floor(Math.random() * (maxInt - minInt + 1)) + minInt); 3} 4 5console.log(createRandomInt(1, 3)); 6console.log(createRandomInt(1, 3)); 7console.log(createRandomInt(1, 3)); 8console.log(createRandomInt(1, 3)); 9console.log(createRandomInt(1, 3)); 10console.log(createRandomInt(1, 3)); 11console.log(createRandomInt(1, 3)); 12console.log(createRandomInt(1, 3)); 13console.log(createRandomInt(1, 3)); 14console.log(createRandomInt(1, 3));
Math.random()
に偏りがない前提で考えるならば、
- 「正の数/負の数」からランダムに偏りなく選びます
- 「1,2,3」からランダムに偏りなく選びます
更新履歴
- 2017/02/03 19:44 算術演算子型コードを追記
- 2017/02/03 21:30 「数学的にエレガント」の定義に言及
- 2017/02/03 21:41 配列からランダムに値を得るコードを追記
- 2017/02/03 22:21 配列からランダムに値を得るコードの別解を追記
Re: miu_ras さん
投稿2017/02/03 04:49
編集2017/02/03 13:29総合スコア18189
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/04 05:01
退会済みユーザー
2017/02/04 13:24
2017/02/06 02:22
0
数学的かはわかりませんが、その他の方法として、、、
// 1〜6を取得して3より大きければ7を引く var v = Math.ceil(Math.random() * 6); if(v > 3) { v -= 7 } // 1〜3を取得して、ランダムに符号を変える var v = Math.ceil(Math.random() * 3); if(Math.random() < 0.5) { v *= -1 }
投稿2017/02/03 00:17
総合スコア1186
0
「-3≦x≦3(端を含むかはそこまで気にしなくてもいい)の一様乱数を生成して、出た小数を無限大に丸める」という方法も考えられます。
ただ、運悪く(?)ちょうど0が出たときはどうするかは、ちょっと検討が必要かもしれません。
投稿2017/02/03 00:10
総合スコア145967
0
- MDNのソースそのままの引用で済む。
- ランダムで出したい数値の範囲が変更されても、配列内の数値を変更するだけでよくメンテナンスしやすい。
配列を使わない理由がないですね。
大量の数列を用意する必要があり、配列に規則性がある場合は、その配列を生成するための関数を作ればいいと思います。今回の場合はそこまでする必要はないですね。
javascript
1function getRandomInt(min, max) { 2 return Math.floor( Math.random() * (max - min + 1) ) + min; 3}; 4 5const arr = [-3, -2, -1, 1, 2, 3]; 6 7let i = getRandomInt(0, arr.length-1); 8 9console.log(arr[i]);
規則性のある配列をまず作り、そこから必要ない数値を除外するというアプローチも簡単にできます。
javascript
1// [-3, -2, -1, 0, 1, 2, 3] の配列を作り、0を除外 2const arr = [...Array(7).keys()].map(v => v - 3).filter(v => v); 3 4console.log(arr) // [-3, -2, -1, 1, 2, 3]
javascript
1// 1~10の配列を作り、3、9を除外 2const arr = [...Array(10).keys()].map(v => v + 1).filter(v => v !==3 && v !==9); 3 4console.log(arr) // [1, 2, 4, 5, 6, 7, 8, 10]
投稿2017/02/04 03:14
編集2017/02/04 03:30総合スコア2092
0
まず前提として「数学的な方法」とはどのようなものであるか定義しないことには具体的な答えはでません。
コンピュータで作る乱数は基本的に疑似乱数に過ぎません(例外はハードウェア乱数生成)。また、乱数の生成過程には様々なものがあります。一様分布、正規分布などモデルがわからないことには確定しません。そして、これが決まれば「候補を配列に持つ」というのは非常にスマートだと思います。
ちなみに、私の出身研究室では、「教授が不確定な外乱要素を乱数で補正するという発明をした」とされており、巻き添え食らわせらかけました。なんか、この発明で特許を取得し、大金を動かしたらしいです。シミュレートするならともかく補正できるのはおかしいだろう、と思います。ただし、万が一にこの外乱要素と疑似乱数の生成過程が同一であるなら可能性もあるかもしれません。もっとも、私は別の可能性を考えましたがね。
投稿2017/02/03 14:11
総合スコア4830
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/04 03:13
2017/02/04 13:37
0
すみません、全然ダメでした orz
randomを一回だけの呼び出しにして1ラインで、ややこしくない方法でというのは何かありそうな気がしますが以外に難しいですね ><
シンプル(1ライン)かつややこしくないというあたりを狙うならこんなんでもいいんでしょうか
var result = Math.ceil(Math.random()*6-2.5)
追記:ちなみにjavaなどの感覚でceilの結果が浮動小数だと整数として使えないかなと思って
browserのconsoleを使って
var a = [1, 2, 3]
なんてしてからrが1になったときに
alert(a[r])
とやったら2が表示されたので「こんなんでもいいのかな」と思いました。
テキトーな回答で恐縮ですが。
投稿2017/02/03 02:57
編集2017/02/03 03:19総合スコア18402
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/03 03:09
2017/02/03 03:13
2017/02/04 02:34
0
1~6の乱数を取得して、3引くってのはどうでしょう?相当シンプルだと思いますが。
投稿2017/02/03 01:02
総合スコア1046
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/03 01:07
2017/02/03 01:14
2017/02/04 00:48
2017/02/04 02:29
0
https://teratail.com/questions/64398
上記質問に対するalgさんの回答のパクリですが、、、
c#
1List<int> source = new List<int>() {-3,-2,-1,1,2,3}; 2 3Random random = new Random(); 4int randomIndex; 5int randomValue; 6 7// 確認 8for ( int i = 0; i < 100; i++ ) 9{ 10 randomIndex = random.Next(source.Count); 11 randomValue = source[randomIndex]; 12 Console.WriteLine(randomValue); 13}
投稿2017/02/03 00:15
総合スコア648
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。