質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

1746閲覧

ループを使わずに偏りランダムを行う方法

退会済みユーザー

退会済みユーザー

総合スコア0

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/09/16 12:00

編集2020/09/16 12:24

ゲームのガチャ等では偏りランダムは欠かせないものとなっています。
私の場合以下のようなやり方で行っています。

Aの確率は80% Bの確率は19.5% Cの確率は0.5% の場合
各データの確率を分数のように通分し全て整数にします
BCが少数の確率がなのですべて10倍します。
A800B195C5となります。
➀で求めた各データの値を分数のように約分します
この場合、各データの➀の値はすべて5の倍数なので、すべて5で割ります。
A160B39C1となります。
➁で求めた各データの値分を配列に代入します
Aは160なので配列にA160個代入。B39個代入。C1個代入。
配列の中身は ['A', 'A', 'A', 'A', ... 'A', 'B', 'B', 'B', 'B', ... 'B', 'C'] のようになります。
偏りランダムを行います
配列[Math.floor(Math.random() * 配列.length)] で取得します。

js

1// *** 偏り *** // 2let table = { 3 "A": 80.0, 4 "B": 19.5, 5 "C": 0.5 6}; 7 8// *** 手順➀ *** // 9while (true) { 10 let ok = true; 11 for (let key in table) { 12 if (!Number.isInteger(table[key])) { 13 ok = false; 14 break; 15 } 16 } 17 if (ok) { 18 break; 19 } 20 for (let key in table) { 21 table[key] *= 10; 22 } 23} 24 25// *** 手順➁ *** // 26function GCD(array) { 27 function call(a, b) { 28 return (b ? call(b, a % b) : a); 29 } 30 let ans = array[0]; 31 for (let i = 1; i < array.length; i++) { 32 ans = call(ans, array[i]); 33 } 34 return ans; 35} 36let div = GCD(Object.values(table)); 37for (let key in table) { 38 table[key] /= div; 39} 40 41// *** 手順➂ *** // 42let output = new Array(); 43for (let key in table) { 44 let amount = table[key]; 45 for (let i = 0; i < amount; i++) { 46 output.push(key); 47 } 48} 49 50// *** テスト *** // 51let items = {}; 52for (let i = 0; i < 1000; i++) { 53 54 // *** 手順➃ *** // 55 let key = output[Math.floor(Math.random() * output.length)]; 56 57 // *** カウント *** // 58 if (!items.hasOwnProperty(key)) { 59 items[key] = 0; 60 } 61 items[key]++; 62 63} 64console.log(items);

ここのページを参考にいろいろと改良しました。

問題点

このやり方では超低確率での偏りランダムを行う際、➂の手順で大量のデータを入れる必要があります。
環境によってはメモリ不足などのパフォーマンスに影響を及ぼします。
その為、著しく低い確率の偏りランダムを行うのは不向きです。
ループを使わずにパフォーマンスも安定している偏りランダムを行う方法についてご教授ください。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2020/09/16 12:01

まず自身がやったこと(コード)を提示し、それについての問題点を指摘してもらった方が良いかと思います。
退会済みユーザー

退会済みユーザー

2020/09/16 12:25

了解しました。
guest

回答3

0

普通に考えれば、

JavaScript

1function rabc(){ 2 const r = Math.random(); 3 if(r<0.8) return "A"; 4 if(r<0.8+0.195) return "B"; 5 return "C"; 6}

テーブルにすると、

JavaScript

1function rabc(){ 2 const a = [0.8,"A",0.8+0.195,"B",1,"C"]; 3 const r = Math.random(); 4 for(let i=0; i<a.length; i+=2){ 5 if(r<a[i]) return a[i+1]; 6 } 7}

投稿2020/09/16 12:28

編集2020/09/16 12:30
otn

総合スコア84533

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

例の場合は、配列にAを160個、Bを39個、Cを1個入れています。これがわかるのなら、わざわざ配列を見に行かずとも、配列の0159番がA、160198番がB、199番がCだとわかることになります。…であれば、配列に入ったデータなど不要ということになります。
データ数を減らすために②で「約分」をしているのでしょうが、データが不要ならば約分をする必要もなくなります。たとえ1億分の1の確率であろうとも、くじを1億本も用意する必要はありません。

投稿2020/09/17 20:02

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/09/18 11:50

確かによく考えてみたら不要でした。深く考えすぎてしまいました(+_+)
guest

0

方式方法
くじ引き方式200個の要素を持つ配列にA,B,Cを格納 -> Fisher–Yates shuffle
乱数方式Math.floor(Math.random()*200) -> A,B,Cを数値範囲で対応させる

メモリを気にされていますが、200個の配列は大してメモリを消費しませんし、200回に1回くじを生成する処理が高負荷とは思いません。

Re: CantRunRiver さん

投稿2020/09/16 14:13

think49

総合スコア18162

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/09/17 13:08

> メモリを気にされていますが、200個の配列は大してメモリを消費しませんし、200回に1回くじを生成する処理が高負荷とは思いません。 200個はあくまで↓の説明をするための例です。 > ゲームのガチャ等では偏りランダムは欠かせないものとなっています。 > 私の場合以下のようなやり方で行っています。 問題点で挙げた話をしています 例えば、超低確率(0.00000001%)なら1億回の要素を追加することになります。 分かりずらくてすいませんm(._.)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問