3

次のコードを使用して 64 ビットの乱数を生成しようとしています。数値をバイナリで表示したいのですが、問題はすべてのビットを変化させることができないことです。数値はできるだけバラバラにしてほしい

void PrintDoubleAsCBytes(double d, FILE* f)
{

f = fopen("tb.txt","a");

  unsigned char a[sizeof(d)];
  unsigned i;
  memcpy(a, &d, sizeof(d));
  for (i = 0; i < sizeof(a); i++){
    fprintf(f, "%0*X", (CHAR_BIT + 3) / 4, a[sizeof(d)-1-i]);

  }
   fprintf(f,"\n");
 fclose(f); /*done!*/
}

int main (int argc, char *argv)
{

int limit = 100 ;
double a, b;                
double result;
int i ;           
printf("limit = %d", limit );

for (i= 0 ; i< limit;i++)
    {
    a= rand();
    b= rand();
    result = a * b;
    printf ("A= %f B = %f\n",a,b);
    printf ("result= %f\n",result);
    PrintDoubleAsCBytes(a, stdout); puts("");
    PrintDoubleAsCBytes(b, stdout); puts("");
    PrintDoubleAsCBytes(result, stdout); puts("");

    }
}

出力ファイル

41DAE2D159C00000        //Last bits remain zero, I want them to change as well as in case of the result
41C93D91E3000000
43B534EE7FAEB1C3
41D90F261A400000
41D98CD21CC00000
43C4021C95228080
41DD2C3714400000
41B9495CFF000000
43A70D6CAD0EE321

どうすればこれを達成できますか?ソフトウェアコーディングの経験があまりありません

4

3 に答える 3

3

Java では非常に簡単です。

Random rng = new Random(); //do this only once

long randLong = rng.NextLong();
double randDoubleFromBits = Double.longBitsToDouble(randLong);

CIでは、それを行うためのハック方法しか知りません:)


rand()RAND_MAX は 2^15-1 まで低くなる可能性がありますが、実装で定義されているため、マスクとビットシフトを行うことで 64 のランダム ビットを取得できます。

//seed program once at the start
srand(time(NULL));

uint64_t a = rand()&0x7FFF;
uint64_t b = rand()&0x7FFF;
uint64_t c = rand()&0x7FFF;
uint64_t d = rand()&0x7FFF;
uint64_t e = rand()&0x7FFF;
uint64_t random = (a<<60)+(b<<45)+(c<<30)+(d<<15)+e;

次に、それをユニオンに詰め込み、ユニオンの他のメンバーを使用して、そのビットをdouble. 何かのようなもの

union
{
    double d;
    long l;
} doubleOrLong;

doubleOrLong.l = random;
double randomDouble = doubleOrLong.d;

(私はこのコードをテストしていません)


編集:それがどのように機能するかの説明

まず、srand(time(NULL));シードは現在のタイムスタンプでランドされます。したがって、これは最初に 1 回だけ行う必要があり、以前の RNG シリーズを再現したい場合は、必要に応じてそのシードを再利用できます。

rand()0 から RAND_MAX までのランダムで偏りのない整数を返します。RAND_MAX は、少なくとも 2^15-1 (0x7FFF) であることが保証されています。RAND_MAX が何であるか (たとえば、2^16-1、2^31-1、2^32-1 など) が問題にならないようにプログラムを作成するには、下部以外のすべてをマスクします。 15 ビット - 0x7FFF は、2 進数で 0111 1111 1111 1111、または下位 15 ビットです。

ここで、ランダムな 15 ビットすべてを 64 ビットにパックする必要があります。ビットシフト演算子 は<<、左オペランド (右オペランド) のビットを左にシフトします。したがって、random と呼ぶ最後の uint64_t には、次のように他の変数から派生したランダム ビットがあります。

aaaa bbbb bbbb bbbb bbbc cccc cccc cccc ccdd dddd dddd dddd deee eeee eeee eeee

しかし、これはまだ double としてではなく、uint64_t として扱われています。そうするのは未定義の動作なので、選択したコンパイラで期待どおりに動作することを確認する必要がありますが、この uint64_t を共用体に入れてから共用体の他の double メンバーを読み取ると、(うまくいけば!)それらの同じビットを、ランダムなビットで構成される double として解釈します。

于 2013-04-24T03:08:27.470 に答える
0

使用はこれを使用できます:

void GenerateRandomDouble(double* d)
{
  unsigned char* p = (unsigned char*)d;
  unsigned i;
  for (i = 0; i < sizeof(d); i++)
    p[i] = rand();
}

この方法の問題点は、C プログラムがこの関数によって返される値の一部を使用できない可能性があることです。これらの値は無効または特殊な浮動小数点値であるためです。

ただし、ハードウェアをテストしている場合は、ランダムなバイトを生成し、最初にdouble.

これらのランダム バイトを として扱う必要がある唯一の場所はdouble、ハードウェアによって返された結果の検証ポイントです。

その時点で、バイトを見て、それらが有効な値を表しているかどうかを確認する必要があります。その場合はmemcpy()、バイトを a に変換しdoubleて使用できます。

次に対処すべき問題は、これらの乱数doubles(加算、乗算など) を処理するために必要なオーバーフロー/アンダーフローと例外です。それらを安全かつ確実に検出できるかどうかにかかわらず、プラットフォーム (コンパイラ + CPU + OS) でそれらを処理する方法を理解する必要があります。

しかし、それは別の質問のように見え、おそらくすでに尋ねられ、回答されています。

于 2013-04-24T05:40:56.403 に答える