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

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

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

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Q&A

解決済

2回答

5345閲覧

batファイルの乱数について

lictt

総合スコア3

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

0グッド

0クリップ

投稿2021/10/02 07:46

起動するたびにWindows Terminalの背景を変えようとして、以下のようなbatファイルを作りました。

bat

1@echo off 2 3cd 画像のあるディレクトリ 4set /a ran1=%random%*11/32767 5 6echo %ran1% 7 8if %ran1% == 0 ( 9 copy A.jpg BackGround.jpg 10) 11 12if %ran1% == 1 ( 13 copy B.jpg BackGround.jpg 14) 15 16if %ran1% == 2 ( 17 copy C.jpg BackGround.jpg 18) 19 20if %ran1% == 3 ( 21 copy D.jpg BackGround.jpg 22) 23 24if %ran1% == 4 ( 25 copy E.jpg BackGround.jpg 26) 27 28if %ran1% == 5 ( 29 copy F.jpg BackGround.jpg 30) 31 32if %ran1% == 6 ( 33 copy G.jpg BackGround.jpg 34) 35 36if %ran1% == 7 ( 37 copy H.jpg BackGround.jpg 38) 39 40if %ran1% == 8 ( 41 copy I.jpg BackGround.jpg 42)

しかし、実行してみると、ターミナルを起動してから一回目は8しか出ません。ターミナルを閉じないでもう一度実行するとちゃんと別の数字がでます。これはbatファイルを直接実行してみても、同じでした。仕方ないことなのでしょうか。

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

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

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

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

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

m.ts10806

2021/10/02 09:49

「受付中に戻す」ことができるので、「ベストアンサーを選びなおす」ことも可能です。
guest

回答2

0

ベストアンサー

バッチファイルの先頭に
setlocal enabledelayedexpansion
を入れて試してみて下さい。

<参考>
■ 指定長・個数のランダム数字列生成バッチ(Windows編)
https://qiita.com/real_yaruo/items/8d7c5abe37a73e2fc408

回答に誤りがあった為、訂正しておきます。(コメントで情報提供いただいた方ありがとうございます。)

enabledelayedexpansion(遅延環境変数)は %RANDOM% とは本質的に関係ありません。
(Qiita 記事に書いてあったのは、for文の中で %RANDOM% を使う場合に必要ということでした。)

実行してみると、ターミナルを起動してから一回目は8しか出ません

同じ値が出ている原因ですが、%RANDOM% の結果として、似通った値が返ってきていることが原因です。
以下は %RANDOM% の出力例になります。

19:05:06.97 / 21763
19:05:07.22 / 21767
19:05:37.67 / 21865

この場合ですと、いずれの場合も%random%*11/32767の計算結果として7が出ることになります。

今回の用途(実行する度に壁紙を変える)であれば、余りを求めるのが良いと思われます。
変更前)set /a ran1=%random%*11/32767
変更後)set /a ran1=%random%%%11

ターミナルを閉じないでもう一度実行するとちゃんと別の数字がでます。

(ターミナルとして PowerShell とコマンドプロンプトが選べるかと思いますが、ここではコマンドプロンプトを利用している想定で書かせて頂きます。)

乱数の元となるシードを cmd.exe の起動時に決定している為です。
同じプロセス内(cmd.exe内)では、シードが決定した後は、疑似乱数が正しく機能する為、実行する度にランダムな値が表示されます。

%RANDOM% がそれ程ランダムでない値を返す理由については下記ブログに記事がありましたので、興味がありましたら参照下さい。

■ As random as I wanna be: Why cmd.exe's %RANDOM% isn't so random
https://devblogs.microsoft.com/oldnewthing/20100617-00/?p=13673

投稿2021/10/02 08:01

編集2021/10/02 17:53
cx20

総合スコア4648

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

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

lictt

2021/10/02 08:18

ありがとうございました
lictt

2021/10/02 08:51

今気づいたんですけど、gauさんのよりcx20さんの方がサイトを貼ってあったのでベストアンサーにしようとしていたんですけどgauさんをベストアンサーにしてしまいました。すみません。
Zuishin

2021/10/02 08:56

ベストアンサーは変更できます。 この回答で解決するのであれば変更してください。 しかしその前に、偶然ではなく本当に 8 しか出ないのかを十分な回数試行してください。 こちらの実験では、ちゃんと乱数が出ていますし、この方法で解決するかどうかも疑わしく思っています。
cx20

2021/10/02 08:58

すみません。私の回答も正しくないかもしれません。 試した所、enabledelayedexpansion 無しでも、乱数は取得できているようです。 ただ、PowerShell とコマンドプロンプトで表示される乱数に偏りがあるようです。 環境による問題なのか、まだわかっていませんが、自分の環境だと、 PowerShell の場合、6680, 6886, 6693, 6696, 6699, ... コマンドプロンプトの場合、31781, 2738, 1649, 29618, 18021, ... のような結果でした。 したがって、ターミナル(PowerShell)の場合、連続した値に近い結果が返却されている為に、 %random%*11/32767 で計算した結果、同じ値が表示されているように見えているのではないかと思います。
cx20

2021/10/02 09:33

別の案としては、32767で割るのではなく、余りを求める方法にしてみはどうでしょうか? 変更前)set /a ran1=%random%*11/32767 変更後)set /a ran1=%random%%%11 <参考> ■ バッチファイルで余りを計算する https://commandprompt.noyokan.com/command/amari.html
SaitoAtsushi

2021/10/02 09:55

%random% の正確な仕様はドキュメントにないのでよくわかないところはありますが、乱数列の初期化は cmd.exe が起動されるときに行われるようです。 つまり、 cmd.exe (コマンドプロンプト) を起動してその中で何度もバッチファイルを起動すれば乱数列の通りに乱数が得られますが、 PowerShell からバッチファイルを起動した場合にはその都度時刻によって初期化された乱数列の最初の値が得られることになります。 Windows の乱数生成ルーチンは線形合同法で下位ビットを大幅に捨てていて、乱数列の最初の値は時刻に強く依存した値になるので毎回初期化するのだと煮たような値が出てきます。
cx20

2021/10/02 10:14

SaitoAtsushi さん、情報ありがとうございます。参考になります。 > PowerShell からバッチファイルを起動した場合にはその都度時刻によって初期化された乱数列の最初の値が得られることになります。 そのようですね。 コマンドプロンプトから「cmd /c "test.bat"」のように cmd.exe を起動した場合も PowerShell での実行時と同様な結果が見られました。 試した感じだと、ミリ秒までは見ておらず、同一時分秒の場合、同じ乱数が取得できるようでした。 19:05:06.97 / 21763 19:05:07.22 / 21767 19:05:07.43 / 21767 19:05:07.59 / 21767 19:05:07.74 / 21767 19:05:37.67 / 21865
otn

2021/10/02 11:50 編集

> setlocal enabledelayedexpansion は関係ないですね。どういう関係があると思ったのでしょうか。 コメントの通り、(実験によると)初期値が時刻依存なので、短い時間で実行すると同じ値になりますので、余りを使うのがよいと思います。余りを使うと多少偏りが出ますがわずかなので今回のようなケースではよいでしょう。 あと細かいですが、set /a ran1=%random%*11/32767 じゃなくて set /a ran1=%random%*11/32768 ですね。
cx20

2021/10/02 11:32

> は関係ないですね。どういう関係があると思ったのでしょうか。 すみません、参考 URL に enabledelayedexpansion を入れない場合、同じ値を返すとあったので、鵜呑みにしてしました。ちゃんと確認すべきでした。 > ■ 指定長・個数のランダム数字列生成バッチ(Windows編) > https://qiita.com/real_yaruo/items/8d7c5abe37a73e2fc408
cx20

2021/10/02 16:39

> 同一時分秒の場合、同じ乱数が取得できるようでした。 こちらに cmd.exe の %RANDOM% の解説記事がありました。 ■ As random as I wanna be: Why cmd.exe's %RANDOM% isn't so random https://devblogs.microsoft.com/oldnewthing/20100617-00/?p=13673 これによると Windows のコマンドプロンプトの乱数生成のシードには現在時刻が使用されているようです。 > srand((unsigned)time(NULL)); そして time() 関数の分解能が1秒である為、同一時分秒に実行すると同じ乱数を返すようです。
lictt

2021/10/03 09:09

みなさんありがとうございました。
guest

0

どんな言語でも大抵乱数は決まった数がでます
なので、実行時にランダムシードに現在時刻を設定して変化があるようにします

投稿2021/10/02 08:10

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Zuishin

2021/10/02 08:12

バッチファイルでは具体的にどうすればランダムシードに現在時刻を設定できるんでしょうか?
退会済みユーザー

退会済みユーザー

2021/10/02 08:16

cx20さんが提示してますよ
lictt

2021/10/02 08:18

ありがとうございました
Zuishin

2021/10/02 08:18

つまりこの回答は cx20 さんの回答ありきで、そこに含まれていない情報は何一つないということですか? また、具体的にコードのどの部分でランダムシードに現在時刻を設定しているんでしょうか?
YAmaGNZ

2021/10/02 08:32

複数回乱数を求めると2回目以降が変わったりするのでSEED値が変化していないということはないかと思います。
退会済みユーザー

退会済みユーザー

2021/10/02 08:32

Zuishinさん 今確認してみましたが、%random%はターミナル起動後でも毎回違った値になってますね 起動時の秒をランダムシードとして使うようです
Zuishin

2021/10/02 08:50 編集

setlocal enableDelayedExpansion はシードとも現在時刻とも関係ありません。 バッチの独特な仕様で、ループ中に変数が更新できないという設定を更新できるようにするものです。 「遅延環境変数」を検索してみてください。 また、「どんな言語でも」とありますが、シードを手動で現在時刻に設定しなければならない言語は、私は C 言語以外に知りません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問