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

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

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

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

Q&A

解決済

4回答

1181閲覧

Math.random()で1を含めたい。0を含めたくない。

_._

総合スコア32

JavaScript

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

0グッド

1クリップ

投稿2022/03/19 01:10

Math.random()で1を含めたい。0を含めたくない。

Math.random()の値を、

  • 1を含む(0も1も含む)
  • 0を含まない(0も1も含まない)
  • 0を含まない、1を含む(←今のところ必要ないけどついでに)

にしたいです。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/random#examplesを参考にして、

javascript

1// 0を含む、1を含まない 2// 0 <= value < 1 3const random_ge0_lt1 = () => Math.random() 4 5// 1を含む(0も1も含む) 6// 0 <= value <= 1 7const random_ge0_le1 = () => Math.floor(Math.random() * (1000 + 1) ) / 1000 8 9// 0を含まない(0も1も含まない) 10// 0 < value < 1 11const random_gt0_lt1 = () => Math.floor(Math.random() * (1000 - 1) + 1) / 1000 12 13// 0を含まない、1を含む 14// 0 < value <= 1 15const random_gt0_le1 = () => Math.floor(Math.random() * 1000 + 1) / 1000

としてみましたが、

1000の部分をもっと大きい数字にすれば小数の桁数も増えますが、
元のMath.random()よりも情報量が減っている感が不満です。

どうすればいいですか。

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

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

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

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

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

itagagaki

2022/03/19 01:29

目的がわかりませんが。 少なくとも 0 < value <= 1 なら 1 - Math.random() でいいかと。
guest

回答4

0

ベストアンサー

1を含む(0も1も含む)

Math.random()では無理でしょう。

0を含まない(0も1も含まない)

生成して0.0なら再度生成する。

0を含まない、1を含む(←今のところ必要ないけどついでに)

1から引く。

投稿2022/03/19 02:23

otn

総合スコア84423

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

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

0

0も1も含む乱数を作りたい場合、以下のような手順が考えられます。

  1. 「0.5より少し大きく、2進法で書いてきれいに割り切れる数」を事前に用意しておく(これをXとする)
  2. Math.random()を1つ引いて、0.5以上か未満かを判定する
  3. ステップ2で引いた数が0.5未満の場合、改めてMath.random()を1つ引いて、それをX倍したものを結果とする(0≦出る値<X
  4. ステップ2で引いた数が0.5以上の場合、改めてMath.random()を引き、X*(Math.random() + 1)を計算する(X≦出る値<2*X
  5. ステップ4で得られた値が1以下ならそれを出力、1を超えればステップ2からやり直し

投稿2022/03/19 03:32

maisumakun

総合スコア145121

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

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

_._

2022/03/19 06:23

0も1も含むものは簡単な手順では実現できないんですね
ikadzuchi

2022/03/19 07:54

すみません、「2進法で書いてきれいに割り切れる数」という意味が分からないのですが、具体的に例えばいくつですか? また、「Math.random()*xを計算し、1を超えればやり直し」に対する利点が分かりません。
maisumakun

2022/03/19 08:51

> 2進法で書いてきれいに割り切れる数 0.50048828125(1/2+1/2048)のような、浮動小数点数として端数の出ないものです。 > 「Math.random()*xを計算し、1を超えればやり直し」に対する利点 1より大きな数をかけると、数の間隔が広まって、特定の値が出なくなることが考えられます。
ikadzuchi

2022/03/19 09:41

2進法で書いてきれいに割り切れる数について、なるほど、了解です。 1より大きな数をかけると~について、xは0.5強であって1より大きくないですよね? 「掛けた結果が1より大きい」なら分かるのですが、その場合「X*(Math.random() + 1)」では回避できますか?
maisumakun

2022/03/19 11:00

1ちょうどを出さないといけない以上、通常のMath.randomより範囲が広がります。なので、Math.random()1回より大きな情報を得る必要がある、ということが前提となっていますが、それは大丈夫でしょうか? (疑問点の把握を間違えていそうな印象もあるので、もう少し指摘を明確にしていただければとも思います)
ikadzuchi

2022/03/19 16:30

ああああ、すみません、なんだか根本的に勘違いしていました。何故か途中からrandom*Xが1より大きいつもりで考えを進めていたようです。申し訳ありません。忘れてください。
guest

0

そのサンプルコードだと、やりたい事に対して、間違っているコードだと思いますけれど・・・

  • 1以上1001未満を1000で割ると、1以上1.001未満という乱数が発生しますので、整数化した場合などには、発生確率に僅かですが偏りができてしまいます。
  • 0〜999未満の乱数に1を足すと、1〜1000未満という乱数になり、これを1000で割ると0.001〜1.0未満という結果になりますので、0を超える0.001未満の乱数が発生しなくなります。
  • 1〜1001未満を1000で割ると、1.0を超える1.001未満の乱数が発生してしまいます。

この3つとも、乱数としては正常ではないと考えられます。

さて、0を超える1.0以下の乱数ですが、1 - Math.random()でできると思います。

投稿2022/03/19 01:37

編集2022/03/19 01:42
One_of_Arthur

総合スコア75

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

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

0

「0も1も含む」について。
考え方としては、
・乱数を2つ使い、2倍の長さの乱数を用意する
・100...001(2進;以下同様)で剰余を取る
・余りの不均一さはごく僅かなので無視する
とするのがよいでしょう。

ここで、100...001での剰余は、上位-下位の100...001での剰余に等しいです。
参考: 11で割った余りを簡単に出す
つまり、「random-randomを計算し、負なら1.00...001を足す」で求められます。
0になる場合の数が1だけ多いですが、1/2^53程度のずれを気にする場面はまず考えられません。
一応、対処するなら、0になる場合の1つ、例えば「両方0」の場合に好きなだけ再抽選してください。

ただここで問題となるのが、Math.randomの有効な精度が分からないことで、「1.00...001」を具体的にどの桁数にすればよいかが分かりません。
今試した限りではFirefox(98.0.1)では末尾に偶数奇数が正常に分布している一方、Chrome(99.0.4844.51)は末尾に偶数しか出ない(精度が1bit少ない)ようでした。
また、調べていて見つけたのですが、2010年にはWebkit系の精度は30bitしか無かったようです。→JavaScriptの乱数の精度の話
環境を決め打ちして精度を決めるか、どの環境でも最低限確保できる精度を見つけてそれ以降を事前に捨てておくか、このページにあるように2つ乱数を連結して確実に53bitあるようにしておくか、いっそのこと乱数生成ルーチンを自作するかといった対処法が考えられます。

あと「0も1も含まない」も上記の100...001での剰余を11...111での剰余に変えればできますね。11...111での剰余も九去法と同等なので楽です。再抽選が気になるなら。

投稿2022/03/19 09:31

ikadzuchi

総合スコア3047

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問