Yuki Nakata's Blog

One color just reflects another

2016年01月

linux glibcのrand関数のソースコードを読んでみましょう。

どうやって乱数を生成しているのか調べてみましょう。全く怖くありません。

まず乱数についてですが、真性乱数と擬似乱数に分類されます。glibcの乱数は周期性があるため擬似乱数となります。優秀な擬似乱数としてはメルセンヌ・ツイスタ乱数があります。暗号に使われるのは真性乱数の方ですね。難しそうな説明はここまで。w

glibc ダウンロードディレクトリ glibc-2.22.tar.gz

rand関数は解凍してstdlibディレクトリのrandom.cとrandom_r.cに書かれています。

ソースコードを読む、というよりパクって実装して動かしてみると理解できます。

まず今は使われていない昔のrand関数を書いていきます。
oldrand.c

#include <stdio.h>
#include <stdlib.h>

/* x**31 + x**3 + 1.  */
#define    TYPE_3        3
#define    BREAK_3        128
#define    DEG_3        31
#define    SEP_3        3

//実はこの乱数テーブルをいじっているだけ 昔の乱数は2番目の-1726662223しか使っていない
static int32_t  randtbl[DEG_3 + 1] =
  {
    TYPE_3,

    -1726662223, 379960547, 1735697613, 1040273694, 1313901226,
    1627687941, -179304937, -2073333483, 1780058412, -1989503057,
    -615974602, 344556628, 939512070, -1249116260, 1507946756,
    -812545463, 154635395, 1388815473, -1926676823, 525320961,
    -1009028674, 968117788, -123449607, 1284210865, 435012392,
    -2017506339, -911064859, -370259173, 1132637927, 1398500161,
    -205601318,
  };

static struct random_data unsafe_state =
  {
    .fptr = &randtbl[SEP_3 + 1],
    .rptr = &randtbl[1],

    .state = &randtbl[1],

    .rand_type = TYPE_3,
    .rand_deg = DEG_3,
    .rand_sep = SEP_3,

    .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])]
};

void oldrand(struct random_data *buf, int *result)
{
  int *state;

  state = buf->state;
  int val = state[0];
  val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;  //randtbl[1]をごちゃごちゃいじっているだけ
  state[0] = val;
  *result = val;
}

int main()
{
  int i, result;

  for (i = 0; i < 10; i++) {
    oldrand(&unsafe_state, &result);
    printf("oldrand = %d\n", result);
  }

  return 0;
}

$ gcc oldrand.c -o oldrand
./oldrand
oldrand = 897822358
oldrand = 105331223
oldrand = 617672196
oldrand = 1888665581
oldrand = 1128537634
oldrand = 1434149043
oldrand = 980477552
oldrand = 1927835113
oldrand = 1772747374
oldrand = 1723946255

これが昔のrand関数です。randtblという乱数テーブルを用意していますが、たった一つしか使っていません。
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
ここで数字をいじっているだけです。

次は現在使われている乱数
myrand.c

#include <stdio.h>
#include <stdlib.h>

/* x**31 + x**3 + 1.  */
#define    TYPE_0        0
#define    TYPE_3        3
#define    BREAK_3        128
#define    DEG_3        31
#define    SEP_3        3

//実はこの乱数テーブルをいじっているだけ ポインタを使って順送りしているだけ。最後まで行ったら最初に戻る
static int32_t randtbl[DEG_3 + 1] =
  {
    TYPE_3,

    -1726662223, 379960547, 1735697613, 1040273694, 1313901226,
    1627687941, -179304937, -2073333483, 1780058412, -1989503057,
    -615974602, 344556628, 939512070, -1249116260, 1507946756,
    -812545463, 154635395, 1388815473, -1926676823, 525320961,
    -1009028674, 968117788, -123449607, 1284210865, 435012392,
    -2017506339, -911064859, -370259173, 1132637927, 1398500161,
    -205601318,
  };

static struct random_data unsafe_state =
  {
    .fptr = &randtbl[SEP_3 + 1],
    .rptr = &randtbl[1],

    .state = &randtbl[1],

    .rand_type = TYPE_3,
    .rand_deg = DEG_3,
    .rand_sep = SEP_3,

    .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])]
};

void myrand(struct random_data *buf, int *result)
{
  int *state;


      int32_t *fptr = buf->fptr;
      int32_t *rptr = buf->rptr;
      int32_t *end_ptr = buf->end_ptr;
      int32_t val;

      val = *fptr += *rptr;
      /* Chucking least random bit.  */
      *result = (val >> 1) & 0x7fffffff;  //ここで数字をいじる。他はポインタの書き換えでしかない
      ++fptr;
      if (fptr >= end_ptr) {
           fptr = state;
            ++rptr;
        } else {
           ++rptr;
          if (rptr >= end_ptr)
           rptr = state;
        }
      buf->fptr = fptr;
      buf->rptr = rptr;

}

int main()
{
  int i, result;

  for (i = 0; i < 10; i++) {
    myrand(&unsafe_state, &result);
    printf("oldrand = %d\n", result);
  }

  return 0;
}
$ gcc myrand.c -o myrand
$ ./myrand
oldrand = 1804289383
oldrand = 846930886
oldrand = 1681692777
oldrand = 1714636915
oldrand = 1957747793
oldrand = 424238335
oldrand = 719885386
oldrand = 1649760492
oldrand = 596516649
oldrand = 1189641421

難しそうですがやっていることはポインタを使って読み込むrandtblのアドレスを書き換えているだけです。

もちろん、これだけだと毎回同じ乱数が生成されます。

srandは与えられた種を元にrandtblのデータを書き換えているだけです。

それで毎回異なる乱数を生成することができるようになります。

仕組みは恐ろしく簡単です。

それよりも注意が必要なのは関数の実態がわかりづらいことです。

random.cの中でsrandが関連付けられています。

weak_alias (__srandom, srand)  とあります。

srandを呼び出すと__srandomに変換されますよ、という意味。

さらに__srandom_r関数へと変換されて、random_r.cファイルの中で定義されています。

つまりsrand 関数は内部では __srandom_r 関数になります。

仕組みはこんなもんです。この調子でglibcのソースコードを読んでいきましょう。

今日は三国志13の発売日でした。すっかり忘れていました。

三国志13が大炎上しています。ダウンロード版とパッケージ版の2種類があります。
ダウンロード版は0時からダウンロードできると説明されていたのに、ダウンロードできない。笑
しかもダウンロードできたとしてもプレイできない。一体何を買ったのか?
購入したこのキーは一体何なのか?
ありのまま起こったことを話すぜポルナレフ
アマゾンのレビューが酷いことになっています。
だって去年からずっとこの日を楽しみに待っていたわけですからね。
今は修正されてプレイできるようになっているようです。

 <ーー- ダウンロード版レビューが酷いことに。

私はというと抜かりなくパッケージ版を購入いたしました。

ジャジャーン 三国志13到着しました。

ところがインストールが分かりずらい。SteamをインストールしてSteamアカウントを作らないといけません。

しかもネット環境がないと遊べませんよ。要注意

しかもいきなりアップデート。写真の通り2時間待ちです。
パッケージ版なのにアップデートで待たされるとは不覚です。w
まだ遊んでいないですよ。

こういうドタバタも含めてKOEI三国志プレイというところでしょうか。

その後アップデートも終わり、起動しました。 やったーーーーー。

ちなみにデモでは15FPSでした。笑

動けば問題なし。

念のために三国志13のインストールの仕方を解説しておきます。
三国志13a
Steamを起動して、 左下の「ゲームの追加」をクリック。「Steamでアイテムを有効化をする」をクリック。

 三国志13b
製品コードにSteam CD Keyを入力すると三国志13を有効にすることができます。

パッケージ版はこちら

KINIGAME006

KOEIの三国志13を予約しましたよ。

うろ覚えですが、私の三国志暦を書いて見ます。

三国志2 初めてした三国志ゲーム。シンプルで面白かったです。同盟国からお金を援助してもらえます。
火計が強力で火炎地獄が楽しめます。本当に風向き次第で戦争の勝敗が決まります。

三国志3 プレイしましたが記憶ありません。

三国志4 攻城戦が登場。攻城戦がだるくてつまらない。敵も降伏しない。攻城戦はいらない子だった。

三国志5 陣形が登場。後ろから攻撃を受けると大ダメージ。知力の低い張飛がゴミキャラになりました。張飛は使える陣形が少なく、移動距離が短い。戦場に着いた頃には戦争が終わっています。

6~10 スルー

三国志11 マイベスト。一枚マップ。三すくみになります。敵同士が戦っているところに、割って戦争をしかけることができます。ごちゃごちゃ入り乱れての戦争は楽しかったです。初めて見たときは感動しました。ただ移動と輸送に時間がかかり過ぎるのと、どうして後半マンネリになってつまらないです。

三国志12 華麗にスルー

しゃあないので、三国志13を予約購入しました。

三国志13 ベンチマークデモ
ベンチマークデモがダウンロードできるようになっています。PCの場合動くかどうかチェックした方が良いです。


virtualboxのディスク容量を変更の仕方を説明しています。

virtualboxで仮想OSをインストールした後で、ディスク容量を大きくしたくなることがあります。

仮想ハードディスクのサイズを変更するにはVBoxManageと云うコマンドを打たないといけません。

macの場合、VBoxManageは/Applications/VirtualBox.app/Contents/MacOS/
に入っています。

試しにubuntu-12.04のディスク容量を15GBから倍の30GBにやってみます。
41
まずは確認。設定からストレージを選びます。ディスク容量が15GBであることを確認。
これを30GBにします。vdiファイルのパスを覚えておきます。

$ cd /Applications/VirtualBox.app/Contents/MacOS/

$ VBoxManage modifyhd ~/VirtualBox\ VMs/ubuntu-12.04/ubuntu-12.04.vdi --resize 30720

$ VBoxManage modifyhd vdiのパス --resize MByte
サイズはメガバイトで指定します。30GBの場合、30 * 1024で計算できます。
 18
サイズがちゃんと30GBになっています。成功ですね。
 

virtualboxで共有フォルダの使い方を説明しています。

私の環境ですが、マックにvirtualboxを使ってlinuxをインストールしています。

macとlinuxでフォルダを共有してファイルを受渡しできたら便利ですよね。

さっそくやっていきましょう。

57
まずマックでフォルダを作ります。sharedfolderという名前のフォルダを作成しました。

05
virtualboxを起動し、linuxを選択し、設定ボタンをクリック。

共有フォルダのタブをクリックし、共有フォルダのパスを追加します。

27
フォルダーのパスでその他を選び、先ほど作成したフォルダーを指定します。

マックの設定はこれだけです。
 
次はリナックス側の設定です。

ハマるとしたら唯一ここです。

ユーザーをvirtualboxグループに加えなければいけません。

$ sudo gpasswd -a user vboxsf
userに自分のユーザー名を指定してください。

Screenshot from 2016-01-22 08-46-05
共有フォルダは /media/sf_sharedfolderとなります。
sf_が接頭語として付きます。 

デジモノステーション2月号 0円simカードゲットしました。の続きです。

オリコのクレジットカードを申し込みました。

Sonetの0円simの登録にクレジットカードが必要なのですが、肝心のクレジットカードを持っていませんでした。 笑

今までネット決済はスルガ銀行のカードで済ませていたのでそれで大丈夫かと思っていたら、ソネットの申し込みで弾かれました。

どうやらスルガ銀行のカードはデビットカードのようで、クレジットカードとは違うようです。

それで急遽クレジットカードを申し込むことになりました。

お正月の1月1日に申し込みまして、正月休みが入ったのでトータル15日くらいかかっています。 

クレジットカード会社もたくさんありますが、審査が通りやすく年会費無料、アマゾンポイントが付くオリコカードに決定。

 card-thepoint_l
ブラックカードでカッコいい。

オリコカードでsonetの0円シムを申し込んだところ、すんなりパスしました。

今からオリコカードを申し込んでもまだソネット間に合うと思いますよ。

昨年末にソニーのVAIOと東芝、富士通のパソコンメーカーが合併するかも、という仰天ニュースが入りました。

パソコンの売り上げが下がっている中、3社生き残るのは無理だから先手を打って先に合併しておこう、ということです。

うまくいかないでしょう。

3社合わさってもダメだと思います。

全くワクワクしません。

3社集まったらどう良くなるんでしょうか。

逆にパソコンの価格は高くなったりして。

もうパソコンの市場は終わっています。

価格コムを見ても5万円程度が売れていて、儲かりません。

テレビの市場と似ていますね。これでは厳しいです。

もうlenovoやASUSに任せてもいいような感じでもあります。

私の認識ではパソコンの本体は使い捨ての時代になったのです。

ユニクロのフリースのようにです。

パソコンも毎年使い捨てです。

パソコンというのはスマホのように3万円くらいで毎年最新のものを出す、というスタイルになったのです。

15万円もするパソコンを発売するというのがおかしいように思います。

パソコンを作っている場合ではないと分析しています。

小型コンピューターであればこれから市場は大きくなっていきます。

絶好調のラズベリーパイを叩き潰すべきだと思うのですが。





 

↑このページのトップヘ