稲枝の押入れ

いなえが適当なことを書いては、しまっておく場所

「いじめ」について考える時の前提のお話

少し前に大きなニュースとして上がったりしていた「いじめ」に関する事件、それらについて語られる文脈で、その個別具体的な事件についてだけでなく、「いじめ」一般の話がなされるのを見かける。

全てに当てはまるわけではないとしても、「いじめ」というものについて考えるにおいて、一般的な「いじめ論」というのはそれなりの意味はあると思う。

勿論ネット上の匿名同士でボソボソ言ってるだけで問題が直接なくなることは無いだろうが、そもそも議論にならなくなったらそれは「問題」ではなくなってしまう。いじめはいけないことだ、という言うだけなら簡単のこの当たり前のことが、当たり前でなくなってしまう。それはマズい。不当な扱いというものを人一倍嫌う僕個人の感情としては、そんなのはとてもじゃないが許せないし、許されるものじゃ無い、と思う。

さて、というわけでいじめの一般論について議論すること自体には僕はさほどの疑問は感じてい無い。ただし、その議論の内容については度々疑問に思うことがある。

例えば、そのいじめについて、責任の所在が議論される。「いじめた側が悪い」「いじめた側にも何か事情があったかもしれない」「いじめられた側にも責任はあるのでは無いか」「いじめの原因はいじめられた側にもある」。こういった感じで議論をしているのを見ると、まず僕は責任と原因を切り分けるべきではないか、と考える。

「いじめられた側にもいじめの原因があるので責任はいじめられた側にもある」というのは、つまりは「いじめられる理由」とでもいう原因のようなものがあれば、いじめたとしてもそのいじめの責任の一端をいじめられた側に負わせて、いじめた側はその責任を一部言い逃れする事が出来る、といっているのと同じことである。

僕はこれは問題であると思う。こういう構造が認められてしまうと、ただでさえ報復等が怖くていじめを他人に相談できないいじめられた人が、「自分にもその責任の一端があるとして責められるかもしれない」とさらに相談をすることを萎縮させてしまう。

それとは反対に心の弱い人がいじめに踏み切るハードルを下げてしまう。自分だけが悪いのではないのだ、と思うと心の弱い人はそこに逃げてしまいかねない。それでは誰もが不幸になるだけだ。

そしてそもそも、僕はいじめられた側に一切の責任はないと思う。

原因があるから責任もある、というのは論が飛躍しすぎていると思う。これは相当因果関係の話になるので詳しくは割愛するが、次のような例がある。

結婚して幸せ太りした夫のAさんがダイエットに運動を始めようとしていたところ、友人に誘われたので山登りを始めた。やってみると楽しく、Aさんはすっかりハマってしまった。翌年とある山に登っている最中に転落事故にあい、Aさんは死亡した。

この例では、例えばAさんは結婚しなければ太らなかったからダイエットに運動を始めようとなんてしなかったかも知れないし、友人が誘わなければ山登りではなくフットサルを始めていたかもしれない。そうすればAさんは死ななかったかもしれない。

こう見ると、Aさんが死亡する原因として遠いにしたって、Aさんの奥さんが結婚したという行為と、Aさんの友人が山登りに誘ったという行為が挙げられる。

では、奥さんと友人にAさんが死んでしまった事について責任があるのだろうか?

僕は少なくともそうは思わない。

原因があったからといって直ぐに責任に飛びつくのは合理的でないと思う。

原因と責任は分離して考えるべきだ。

例え原因がいじめられた側にあったとしても、いじめた責任はいじめられた側には無い。

ではいじめた側にすべての責任があるのかというと難しいところではある。いじめた側も心が弱かったのだろうし、もしくはそのいじめを助長するような何かがあったのかもしれない。しかしここではその話はしない。

僕が言いたかったのは原因があったからといってそこに責任もあると安直に考えないで欲しいということ、つまり原因と責任は分離して考えよう、ということだ。

そしてもし可能なら、責任という言葉とは縁遠い形で問題の解決が図れたら良いのにな、と思うしそういったことにももっと議論が活発になればな、と思う。

ウィンドウの自動整列ショートカットキーが使えない場合の対処法

最近ディスプレイが3枚に増え、以前にも増してウィンドウを動かすショートカットキーを頻繁に使うようになりました。

その(Windows7の)ショートカットキーというのは

  • Windows ロゴ キー + 左方向キー
    画面の左側にウィンドウを固定する
  • Windows ロゴ キー + 右方向キー
    画面の右側にウィンドウを固定する
  • Windows ロゴ キー + 上方向キー
    ウィンドウを最大化する
  • Windows ロゴ キー + 下方向キー
    ウィンドウを最小化する
  • Windows ロゴ キー + Shift + 上方向キー
    画面の上下にウィンドウを拡大する
  • Windows ロゴ キー + Shift + 左方向キーまたは右方向キー
    モニター間でウィンドウを移動する

(こちらから引用)

といったWindows ロゴ キーと矢印キーを主に組み合わせた様なショートカットキー達です。

頻繁に使うようになって、手にも馴染んできた所で、ノートパソコンを使う機会があったのですが、そちらで何故かこれらのショートカットキーが使えなくて困惑したので、簡単な話でしたが解決法を残しておきます。

デスクトップ環境はWindows7、ノートパソコンはWindows8なのでその違いなのかな?とも思いましたが、調べてみたらWindows8にもこれらのショートカットは(一部なくなっているようですが?)ある模様。

さて何が原因かと考えたところで、思いつきでウィンドウを画面の端に持っていって自動整列をしようと試してみるも出来ない。もしやコレのせいでは?と思い試してみたらまさにそれが原因でした。

具体的に書くと、「コントロール パネル>コンピューターの簡単操作>コンピューターの簡単操作センター>マウスを使いやすくします」から、「ウィンドウが画面の端に移動されたとき自動的に整列されないようにします」のチェックを外すと無事にこれらショートカットキーが使えるようになりました。

画面の小さいノートパソコンで幾つかのウィンドウを開きたい場面では、時にこの自動整列機能は邪魔なのですが、ショートカットキーは使いたいので困ってしまいました。これWindows10とかでは直ってるんでしょうか?

設定に依存せずショートカットキーは使えてほしいですね…

Rigidbodyをスリープモードにしない方法

導入

Rigidbodyとは

UnityにはRigidbodyと言われる物理演算等をしてくれるコンポーネントが有ります。

Unityの物理演算を利用しなくとも、Unityの当たり判定機能を使う為にもこのRigidbodyコンポーネントを少なくとも片方のオブジェクトが持っている必要があるので、Unityを使ったことがある人はおよそほとんどが使ったことがあるであろうコンポーネントです。

Sleepという機能

普通に使っている分には非常に便利なのですが、ちょっとした落とし穴があります。それはスリープ(Sleep)という機能です。

リジッドボディが決められた最低直線、または、回転スピードよりも動きが遅いとき、物理エンジンはそれが休止していると仮定します。これが発生すると、ゲームオブジェクトは衝突されるか力が与えられない限り再び動きません。そのため、それは「スリープ」モードに設定されます。この最適化により、次にリジッドボディが「起きる」 (これは、再動作のこと) までプロセッサーの時間が更新に使われることがありません。 公式より引用

つまり、Rigidbodyは決められた速度(速度、というのは厳密ではない)よりも遅く移動している等の場合、処理軽減のためスリープモードとなり、力を与えられない限り物理演算を行わず動かなくなります

一見それほど問題はなさそうですが、力を与えられない変更、例えばそのスリープとなっているオブジェクトの下の床が消えたといった場合に、オブジェクトは物理演算を行わないのでそのまま宙に浮いたままになったりします。

問題

さて、今回は「OnCollisionStayでプレイヤーの接地判定を取り、その判定がある時だけジャンプが可能になる」という実装をしようとしていたのですが、プレイヤーが止まるとスリープになってしまいOnCollisionStayが呼ばれなくてうまくいきませんでした。じゃあスリープしないようにしよう!となったわけです。

スリープをしないようにしよう!

SleepingModeがない!!

さてここまではよくある話なのですが、僕はここで徐にインスペクタでSleepingMode(スリープする条件を指定する項目)をNever Sleep(スリープを無効にする)にしようとしました。処理が重くなるので本来推奨されないのですが、面倒なのでそもそもスリープしなくしてしまいたかったのです。

しかし、インスペクタを見てもSleepingModeがありません。

以前に使った事があったので(白目)おかしいなと思いながら調べてみるとどうやらRigidbodyにそんなものはないらしい。

え?うそ?前使ったよ?バージョンアップでなくなったの?と思って「Rigidbody never sleep」とかで検索。

結論から言うとRigidbodyにはSleepingModeはなく、Rigidbody2Dのみにあるということらしいです。

なんじゃそりゃ、という感じなのですが、3Dの処理はやはり大変なので簡単にNever Sleepにはされたくないんでしょうかね。

それでもNever Sleepにしたい!!

でも僕はSleepしないようにしたい…

調べるとWakeup関数(強制的にスリープモードを解除する関数)を毎フレーム呼んだり、IsSleeping関数(スリープモードかどうかを返す関数)で判定して、スリープモードの時はWakeUp関数を呼んだりしてるのを見つけたんですが、毎フレーム呼んだりするのはなんとなく抵抗が…

もう少しスマートに出来ないかなと思って公式マニュアルをみていた所、RigidbodysleepThresholdというメンバ変数を発見。

スリープをするのは決められた速度(上述の通り厳密ではない)よりも遅く移動している時と言いましたが、大雑把に言うとこの変数はそのスリープをする決められた速度を規定する変数です。

よって例えば、sleepThresholdを-1とかにすると、「速度が-1より小さくなった時にスリープする」=「速度は0以上なのでスリープしない」となって、Start()内で一回rigid_body.sleepThreshold=-1;みたいな感じで書いてやればずっとスリープしなくなるわけです。

取り敢えずこんな方法でスリープを回避できるようにはなったんですが、急に思いついた方法(かつ正確に理解できているかわからない)なのでどういう副作用があるかわからないというのと、スリープを切るともちろん処理は重くなるので、使用する場合は自己責任かつあまり使わないようにした方がいいかな、と思います。

面倒なのでプレイヤーだけなら大丈夫かな?とか思って僕は使っちゃいますが。

DXライブラリを使って、VS2015でゲームのアイコンを変える方法

導入

こんにちは。

ふと、そういえば前々からつけるつけると言ってたゲームのアイコンをつけてなかったなあと思い、DXライブラリを暫くぶりに書いていたのですが、こちら公式情報には「VisualC++ 2005 Express Edition ~ Visual Studio Express 2013 for Windows Desktop の場合」しか書いていない。

自分の環境はVS2015だったので、.exeのアイコンを変えるだけならこのやり方でいけたものの、SetWindowIconID関数を使ったタスクバーやウインドウの左上端に表示されるアイコンの変更はうまくいきませんでした(このページにあるようにresource.hが自動生成されなかった)。

調べたらすぐ出てきたものの備忘録として残しておくと、簡単に言うとさっきのSetWindowIconID関数のページにある「Borland C++ の場合」と同じ方法でいけました。

全体の流れ

つまり全体としては以下の手順で進めると.exeのアイコンとウィンドウタスクバーやウインドウの左上端に表示されるアイコンの書き換え出来ることとなります。

アイコンの準備

1. 縦横32ドット、256色(8ビット)のアイコンファイル(拡張子.ico)を作成する。(『アイコン用ユーティリティ』等でWEB検索するとアイコンを作成するためのソフトが色々見つかるらしいです。GIMPでも書き出せたので僕はGIMPを使いました) 

2. そのアイコンファイルをVisualStudioのプロジェクトファイル(拡張子.sln)が あるフォルダに保存する。

テキストファイルの準備

3. 同様にプロジェクトファイルがあるフォルダに任意の名前をつけたテキストファイルを作成する。

4. そのファイルをメモ帳等のテキストエディタで開き、中身に次のように入力して保存して下さい。

ここに任意の自然数(アイコンID) ICON "ここにアイコンファイルのファイル名"

例えば

333 ICON "icon.ico"

といった感じ。*1

5. 保存したファイルの拡張子がおそらく.txtになっていると思うが、それを.rcに変更する。

VSに追加

6. プロジェクトを VisualStudioで開き、プロジェクト』→『既存項目の追加』で、追加ファイル選択ダイアログを表示して、作成した拡張子が.rcのファイルをプロジェクトに追加します。

7. 次にビルドした時には作成される実行可能ファイルのアイコンがオリジナルのアイコンになるのでそれを確認する。

SetWindowIconID関数を使う

8. SetWindowIconID()関数をゲームの初期化部分に書き、引数に.rcファイルで指定したアイコンIDを渡してやる。さっきの例なら、

SetWindowIconID(333);

と書く。

*1:勿論自然数ならなんでもいけるってわけではない(ハード資源にも限界がある)のでそのあたりを考えた数にしないといけないけどその辺はつっこまないで

__PRETTY_FUNCTION__マクロが使えない

__FUNCTION__

ちょっと気になることがあって小さい規模のコードを書いていたのだが、デバッグの時に今いる関数が表示できたら楽だなと思い、そんなマクロがあった気がするとか思いながら適当な文字列打ってたら__FUNCTION__マクロをサジェストに発見。

しかしこいつは関数の名前しか返してくれない。オーバーロードされた関数が複数あって、その中で__FUNCTION__マクロを使うような事があったら、実際にはどの関数が走っているのかがわからない。

__PRETTY_FUNCTION__

そんなわけで、型や引数の型なんかも返してくれるものないかなと思ったら__PRETTY_FUNCTION__マクロというものを発見。こいつは型や引数の型も返してくれるらしい。

よしこれだと書いてみると

C2065 '__PRETTY_FUNCTION__': 定義されていない識別子です。

とのこと。

こういった所謂「事前定義済みマクロ」はどうもコンパイラの独自実装のことが多いらしいので、そのへんが関係しているのかも?と思ったら、VSのサジェストでもちゃっかり出てきている。でもコンパイラさんはこんな識別子は知らないらしい。

ちょっと調べてみたらg++の独自実装だとか書いてあったけど、ますます何故サジェストが効いたのかわからなくなってきた。

原因が知りたいところではあるけれど、その前にまずは何とか動くようにしたい。

__FUNCSIG__

他にも型や引数の型を返してくれる事前定義済みマクロがないかなあと思って探していたら__FUNCSIG__マクロなるものを発見。これを使ったらうまく行った。

試しにmain関数の中で使ってみたら

int __cdecl main(void)

こんな感じで実行中関数の情報をくれた。

マイクロソフトの公式情報によると、__FUNCSIG__マクロは

__FUNCSIG__ Defined as a string literal that contains the signature of the enclosing function. The macro is defined only within a function. The __FUNCSIG__ macro is not expanded if you use the /EP or /P compiler option. When compiled for a 64-bit target, the calling convention is __cdecl by default. For an example of usage, see the __FUNCDNAME__ macro.

引用元
日本語がいい人はこっち

てな感じらしい。相も変わらず翻訳が意味わからなかったので原文で。まだ日本語訳してくれているだけありがたいので文句ばかりはいってられないけれど、マイクロソフトのあのわかりにくい翻訳は何とかならないのだろうか…

__func__

余談だけれど、「事前定義済みマクロ」はどうもコンパイラーの独自実装のことが多い、とさっき書いたけれど、その中でもこの関数名を表示する系のもののうち一部は、今では(という書き方をすると怒られそうなので補足しておくと一定の規格からは)規格として定義されているらしい。

例えば、C99では__FUNCTION__と同等の機能のものが__func__として追加されたそうな。ただし、

C++では現時点では定義が無いが、g++やclang/LLVMではC++コンパイル時にも利用できる。 g++の場合、C++で使用した場合は __FUNCTION__ とは違い関数名や引数はクラス名付きで得られる。

引用元

ということで、C++だと同等とは言えないみたいだけど。

まとめ

簡単にまとめると

  • __FUNCTION__
    • 関数の名前のみを得られる
  • __func__
    • C99で定義
    • __FUNCTION__と基本的に同じ
    • C++環境では違うことも?
  • __FUNCSIG__
    • 関数の型と名前と引数の型を得られる
  • __PRETTY_FUNCTION__
    • 関数の型と名前と引数の型を得られる(らしい)
    • VS環境ではコンパイル時にエラーが出て使えない(サジェストには表示される)
  • __FUNCDNAME__
    • 関数の名前を装飾名付で得られる

という感じ。一番下のものはこの記事では触れてませんが気になったら調べてみてください。さっきのMSのページにも書いてます。

あと、ここではわかりやすいように「得られる」と書いたが、厳密には「定義されている」だと思う。関数ではなくマクロなので。

もし__PRETTY_FUNCTION__が僕のVS環境下でコンパイルするとエラーが出るのか、思い当たる人は是非教えていただきたいです…

VisualStudioでコンソールプログラムを実行後、コンソール画面を消さない方法

調べた感じVS2010からどうも「空のプロジェクト」を作るとデフォの状態だとプログラムの実行が終わると自動でウィンドウが消えてしまう様になっているらしい。

最近はGUIの開発が多かったので知らなかったのだけれど、ちょっと試したいことがあって久々にコンソールプログラムを作って実行してみたら一瞬でウィンドウが消えて結果が全く見えなかった。

というわけで、それをどう直したらいいかを調べるのがかれこれ3回目くらいなので、大した分量もないのだが大まかに4つの方法を備忘録的に書いておく。

system("pause");

これはCもしくはC++を使っている場合に使える方法だが、まず、そもそも調べるのが面倒くさい時はsystem関数を使ってしまう。これは簡単に言うと文字列を受け取ってその文字列をコマンドプロンプトに打ち込んだのと同じような動きをしてくれる関数だ。

つまり、

system("pause");

と書くと、pauseコマンド(任意のキーを押すまで処理を中断するコマンド)が実行される。

これをプログラムの最後においておけば、処理が中断されてプログラムが終わらないのでウィンドウが消えなくなる(勿論キーを押すと終わってしまう)。

また、この関数を使うにはC言語なら<stdlib.h>C++なら<cstdlib>をインクルードする必要がある。ただ、<iostream><random>等を辿っていくとその中でそれらがインクルードされていたりするので、ユーザーが自らインクルードせずとも使える場合もある。

入力を待つ

CもしくはC++を使っている場合の方法その2。

Cなら

int hoge;
scanf("%d",&hoge);

C++なら

int hoge;
std::cin>>hoge;

などとして適当な変数に入力を入れるようにする。C言語なら<stdio.h>C++なら<iostream>のインクルードが必要。

ブレークポイント

3つめにもっと面倒くさい時、と言うか特にコードを汚したくない時はVSの機能であるブレークポイントを使ってしまう。これをプログラムの終わりのあたりに設定しておき、デバッグありで実行すれば、おそらくブレークポイントのところにプログラムが達した段階でVSの方に戻ってきてプログラムが一度止まる。ここで出力が確認できる。

ブレークポイントはコードの止めたい位置の左端のあたりをクリックするか、F9キーを押せば設定/解除が出来るはず。

ただし、ブレークポイントで止めた場合はプログラムの画面よりVSのコードの画面が全面に来てしまって、結局画面の出力結果が見辛くなってしまう可能性がある。

設定を変える

もしくはそもそも設定を変えることでこれを回避できる。少し長い間使うプロジェクトならこっちのほうが楽だ。これだとデバッグなし実行(Ctrl+F5)をした時に勝手にプログラムが終了するのを防げるようになる。

やり方は、

  1. ソリューションエクスプーラーで設定したいプロジェクトを右クリックしてプロパティを開く
  2. 左のボックスの中から、構成プロパティ/リンカ/システムを選ぶ
  3. 右のボックスから一番上のサブシステムコンソール(/SUBSYSTEM:CONSOLE)を選択

以上と言った感じ。そもそも何でデフォの設定変わったんですかね。

distributionで乱数の幅を決める時、負の値が指定できない

追記: 自分のアホでミスっていただけでした。結論から言うとresultをunsigned intにしているのに気付いていないままコードを書いていただけでした…お騒がせしました…
よって、この記事は情報が0に近い記事になってしまったわけですが、同じようなうっかりさんが居るかもしれないんのでこのまま残しておきます。

色々あって精度のそれなりな乱数を使いたいなって事でC++11から入ったメルセンヌ・ツイスタを使って乱数生成クラスを作ってたんですが、テストコードを走らせてる段階で何か少し変な挙動を発見。

コードの規模を小さくして検証してみると、どうもdistributionの動きが僕が思ってるのと違うっぽい?

以下0~100の範囲で乱数を100回生成させるようなコードなのですが、これはまあ思った通りに動く。 <コード>

#include<iostream>
#include<iomanip>
#include<random>


int main() {

    std::random_device rand_seed;//非決定論的乱数生成器
    std::mt19937 mt_obj(rand_seed());//メルセンヌ・ツイスタで乱数を生成する
    std::uniform_int_distribution<int>::param_type uniform_parameter(0, 100);//整形する幅を決める
    std::uniform_int_distribution<int> uniform(uniform_parameter);//生成された乱数を指定された幅の一様分布に整形する

    static int calc_num = 0;
    unsigned int result = uniform(mt_obj);


    for (int i = 0; i < 100; i++) {

        if (i != 0) {//初回は飛ばす
            result = uniform(mt_obj);
        }

        calc_num++;

        //表示の幅やレイアウトについて指定して出力している
        std::cout
            << std::setw(5) << std::left << calc_num
            << ":result = "
            << std::setw(5) << std::right << result
            << std::endl;
    }
    return 0;
}



<実行結果>

1    :result =    77
2    :result =    64
3    :result =    63
4    :result =    87
5    :result =    22
6    :result =     3
7    :result =    48
8    :result =    62
9    :result =     0
10   :result =    42
11   :result =    78
12   :result =    52
13   :result =    64
14   :result =    37
15   :result =    51
16   :result =    94
17   :result =    14
18   :result =    24
19   :result =    86
20   :result =    16
21   :result =    25
22   :result =    53
23   :result =    30
24   :result =    45
25   :result =    48
26   :result =    47
27   :result =    17
28   :result =    54
29   :result =    85
30   :result =    99
31   :result =    76
32   :result =    18
33   :result =   100
34   :result =    15
35   :result =    18
36   :result =    17
37   :result =    37
38   :result =    58
39   :result =    77
40   :result =    59
41   :result =    50
42   :result =     4
43   :result =    54
44   :result =    27
45   :result =    66
46   :result =    41
47   :result =    57
48   :result =    63
49   :result =    43
50   :result =    75
51   :result =    10
52   :result =    58
53   :result =    24
54   :result =     3
55   :result =     6
56   :result =    97
57   :result =    37
58   :result =     8
59   :result =    74
60   :result =    35
61   :result =    46
62   :result =    88
63   :result =    66
64   :result =    30
65   :result =    93
66   :result =    33
67   :result =    50
68   :result =    43
69   :result =    19
70   :result =    88
71   :result =    93
72   :result =    63
73   :result =    57
74   :result =    42
75   :result =    87
76   :result =    51
77   :result =    44
78   :result =    62
79   :result =    19
80   :result =    88
81   :result =    10
82   :result =    11
83   :result =    40
84   :result =    12
85   :result =    38
86   :result =    90
87   :result =    11
88   :result =    18
89   :result =    42
90   :result =    78
91   :result =    38
92   :result =     2
93   :result =    35
94   :result =    44
95   :result =    92
96   :result =    92
97   :result =    25
98   :result =     0
99   :result =    18
100  :result =    74

ところが、distributionの範囲にマイナスを含むようにすると動きが少しおかしくなる。

以下は-100~100の範囲で乱数を100回生成するコードだと… <コード>

#include<iostream>
#include<iomanip>
#include<random>


int main() {

    std::random_device rand_seed;//非決定論的乱数生成器
    std::mt19937 mt_obj(rand_seed());//メルセンヌ・ツイスタで乱数を生成する
    std::uniform_int_distribution<int>::param_type uniform_parameter(-100, 100);//整形する幅を決める
    std::uniform_int_distribution<int> uniform(uniform_parameter);//生成された乱数を指定された幅の一様分布に整形する

    static int calc_num = 0;
    unsigned int result = uniform(mt_obj);


    for (int i = 0; i < 100; i++) {

        if (i != 0) {//初回は飛ばす
            result = uniform(mt_obj);
        }

        calc_num++;

        //表示の幅やレイアウトについて指定して出力している
        std::cout
            << std::setw(5) << std::left << calc_num
            << ":result = "
            << std::setw(5) << std::right << result
            << std::endl;
    }
    return 0;
}



<実行結果>

1    :result =   100
2    :result =    72
3    :result =    13
4    :result =    12
5    :result = 4294967282
6    :result =     9
7    :result =    67
8    :result =    91
9    :result =    25
10   :result =    39
11   :result = 4294967232
12   :result =     5
13   :result =    67
14   :result =    45
15   :result = 4294967221
16   :result = 4294967211
17   :result = 4294967266
18   :result =    35
19   :result = 4294967293
20   :result = 4294967256
21   :result = 4294967258
22   :result = 4294967197
23   :result =    68
24   :result =    46
25   :result =    83
26   :result =    71
27   :result = 4294967256
28   :result =     1
29   :result =    63
30   :result = 4294967235
31   :result =    97
32   :result = 4294967291
33   :result = 4294967202
34   :result =    45
35   :result = 4294967272
36   :result =    17
37   :result = 4294967287
38   :result =    33
39   :result = 4294967288
40   :result =     3
41   :result = 4294967271
42   :result =    52
43   :result =    31
44   :result =    16
45   :result = 4294967278
46   :result = 4294967295
47   :result = 4294967204
48   :result =     9
49   :result = 4294967270
50   :result =    44
51   :result = 4294967273
52   :result =    88
53   :result = 4294967221
54   :result =    36
55   :result = 4294967250
56   :result =    29
57   :result =    98
58   :result =    58
59   :result = 4294967277
60   :result = 4294967246
61   :result =    86
62   :result =    66
63   :result =    82
64   :result = 4294967212
65   :result =    60
66   :result = 4294967268
67   :result =     3
68   :result =    83
69   :result =     5
70   :result = 4294967291
71   :result = 4294967263
72   :result = 4294967288
73   :result =    73
74   :result =    88
75   :result = 4294967236
76   :result =     6
77   :result =    39
78   :result =     3
79   :result =    62
80   :result = 4294967212
81   :result = 4294967200
82   :result =    17
83   :result = 4294967224
84   :result =    75
85   :result =     5
86   :result = 4294967289
87   :result =    29
88   :result = 4294967213
89   :result =    59
90   :result = 4294967253
91   :result =     0
92   :result =    10
93   :result = 4294967289
94   :result =    49
95   :result =    37
96   :result =    94
97   :result =    45
98   :result = 4294967293
99   :result = 4294967259
100  :result = 4294967221

と、実行結果がdistributionで定めた範囲の一様分布から外れている。これは負の値はdistributionの範囲に指定できないということなのだろうか?

ただ、std::uniform_int_distribution<int>::param_typeのコンストラクタでは幅の最小最大についてunsigned intではなくintを引数に取っているし、param_typeを使わずにstd::uniform_int_distribution<int>のコンストラクタもunsigned intではなくintを引数に取っている。

仮にこのdistributionが負の値を範囲指定出来ないなら、この辺がunsigned intで引数に渡せと言われそうなものだけど、これは本当に負の値を範囲指定できないという解釈で良いのだろうか。

もちろん、欲しい乱数の幅をズラすのは、得られた範囲にズラしたい分の幅を足したり引いたりすればいい(例えばdistributionの幅を0~200にしておいて、result = uniform(mt_obj);result = uniform(mt_obj) - 100;というようにして、得られた値を-100すれば、-100~100の範囲で乱数は得られる)

でもこんなの標準で出来るようにしておいて欲しい、という願望もあるので、何かできる方法は無いのかなあと思うものの、やはりよくわからない。 `

誰か知っていたら教えて下さい。