13

私はプログラミングが初めてです。

rand() が何をするのか正確に知りたいです。

検索すると、その使用法に関する例のみが得られます。しかし、関数が乱数を生成する方法の各ステップを説明しているものはありません。rand() をブラックボックスとして扱います。

rand() が何をしているのか知りたいです。各ステップ。

rand() の機能を正確に確認できるリソースはありますか? これはすべてオープンソースのものですよね?ソースがなければ、分解で解決します。

乱数を返すことは知っていますが、その数をどのように生成するのですか? 一歩一歩が見たい。

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

4

7 に答える 7

17

現在の glibc の実装は次のとおりです。

/* Return a random integer between 0 and RAND_MAX.  */
int
rand (void)
{
  return (int) __random ();
}

それはあまり役に立ちませんが、__random最終的には次のように呼び出します__random_r:

/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
   congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
   same in all the other cases due to all the global variables that have been
   set up.  The basic operation is to add the number at the rear pointer into
   the one at the front pointer.  Then both pointers are advanced to the next
   location cyclically in the table.  The value returned is the sum generated,
   reduced to 31 bits by throwing away the "least random" low bit.
   Note: The code takes advantage of the fact that both the front and
   rear pointers can't wrap on the same call by not testing the rear
   pointer if the front one has wrapped.  Returns a 31-bit random number.  */

int
__random_r (buf, result)
     struct random_data *buf;
     int32_t *result;
{
  int32_t *state;

  if (buf == NULL || result == NULL)
    goto fail;

  state = buf->state;

  if (buf->rand_type == TYPE_0)
    {
      int32_t val = state[0];
      val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
      state[0] = val;
      *result = val;
    }
  else
    {
      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;
    }
  return 0;

 fail:
  __set_errno (EINVAL);
  return -1;
}
于 2013-09-23T22:21:35.843 に答える
2

確かに、rand は C++ 標準ライブラリではなく、C 標準ライブラリからのものだと思います。どちらのライブラリにも 1 つの実装はなく、いくつかあります。

このページのような場所に移動して、ほとんどの Linux ディストリビューションで使用されている c ライブラリである glibc のソース コードを表示できます。rand.cglibc の場合、やなどの stdlib の下のソース ファイルにありrandom.cます。

uClibc などの別の実装の方が読みやすい場合があります。ここで libc/stdlib フォルダーの下を試してください。

于 2013-09-23T22:24:07.853 に答える
1

最も単純で適度に優れた疑似乱数ジェネレーターは、線形合同法ジェネレーター (LCG)です。これらは次のような式の反復です

X_{n+1} = (a * X_n  +  c) modulo m

定数 a、c、および m は、与えられた予測不可能なシーケンスに対して選択されます。X_0 はランダム シード値です。他にも多くのアルゴリズムが存在しますが、おそらくこれで十分です。

Mersenne Twisterなど、本当に優れた疑似乱数ジェネレーターはより複雑です。

于 2013-09-23T22:21:39.893 に答える
0

私が間違っている場合は修正してください。ただし、この回答は実装の一部を指していますが、 でrand()使用されるものが他にもあることがわかりました。hereから取得した2.32 バージョンから、フォルダーには、単純な線形合同アルゴリズムが使用されていることを説明するファイルが含まれています。フォルダにはともあり、ソース コードの詳細を表示できます。同じフォルダーに含まれている.stdlib[glibc][2]stdlibrandom.crand.crand_r.cstdlib.hRAND_MAX

/* 改良された乱数生成パッケージ。標準の rand()/srand() のようなインターフェイスに加えて、このパッケージには特別な状態情報インターフェイスもあります。initstate() ルーチンは、シード、バイト配列、および渡されるバイト数のカウントを使用して呼び出されます。次に、この配列は初期化されて、乱数生成用の情報とその多くの状態情報が含まれます。状態情報の量に適したサイズは、32、64、128、および 256 バイトです。状態は、initstate() で初期化されたのと同じ配列で setstate() 関数を呼び出すことによって切り替えることができます。デフォルトでは、パッケージは 128 バイトの状態
情報で実行され、線形よりもはるかに優れた乱数を生成します。
合同ジェネレータ。状態情報の量が 32 バイト未満の場合、単純な線形合同 RNG が使用されます。内部的には、状態情報は long の配列として扱われます。配列の 0 番目の要素は、使用されている RNG のタイプ (短整数) です。配列の残りは RNG の状態情報です。したがって、32 バイトの状態情報は、7 次の多項式を可能にする 7 long 値の状態情報を提供します。(注: 状態の 0 番目のワード
情報には、他の情報も格納されています。詳細については、setstate を参照してください)。乱数生成手法は、線形フィードバック シフト レジスタ アプローチであり、三項式を使用します (その方法で合計する項が少ないため)。このアプローチでは、状態テーブル内のすべての数値の最下位ビットが線形フィードバック シフト レジスタとして機能し、周期 2^deg - 1 になります (ここで、deg は使用される多項式の次数であり、多項式がは既約で原始的です)。上位ビットは、下位ビットからの疑似乱数キャリーの影響も受けるため、周期が長くなります。発電機の
全周期は約 deg*(2 deg - 1) です。したがって、状態情報の量を 2 倍にすることは、
発電機の時代。注: deg*(2
deg - 1) は、シフト レジスタの周期が支配的な要因である大きな deg にのみ有効な近似値です。deg が 7 の場合、実際の周期は、この式で予測される 7*(2**7 - 1) よりもはるかに長くなります。*/

于 2021-01-08T03:53:21.783 に答える