8

Random.NextDouble()([0.0,1.0)の範囲のDouble)に大きなInt64(Int64 big = 9000000000L)を掛けて、結果をフロア化して、Randomから取得できる値よりも大きいランダムなInt64値を取得する場合があります。 .Next()(範囲[0、Int32.MaxValue)からのInt32)。

Random r = new Random();
long big = 9000000000L;
long answer = (long) (r.NextDouble() * big);

[0.0、1.0)の範囲のDoubleの一意の値の総数は、生成される可能性のある一意のInt64の数の上限を提供しているように思われます。実際、多くの異なるDoubleが同じInt64にマップされるため、上界と下界は緩くなります。

したがって、知りたいのですが、[0.0、1.0)の範囲のdoubleの一意の値の総数はいくつですか?

「答え」が[0、big)の範囲の値になるように「大きな」が取ることができる最大値と、「答え」の値の分布が均一であるかどうかを教えていただければ、さらに良いでしょう。 Random.NextDouble()は均一です。

編集:ここでのDouble(double)はIEEE 754浮動小数点doubleを指し、Int64(long)とInt32(int)はそれぞれ64ビットと32ビットの符号付き2の補数を指します。


この質問に触発されました:Javaで10桁の一意の乱数を生成します

私はC#を使用しましたが、この質問は言語に依存せず、プログラミングよりも離散数学に関するものですが、主に数学的な好奇心からではなく、数式を使用する場合にのみ数式を使用したいというプログラマーの質問に悩まされています。セキュリティの観点から行うことになっています。

4

6 に答える 6

7

IEEE-754には、11ビットの指数と52ビットの仮数があります。符号ビットが0(正)であると仮定すると、指数の範囲が0x001〜0x3FEの場合、値は0〜1の標準浮動小数点数です。仮数は、格納されていない先頭の1で解釈されます。指数のこれらの0x3FE値のそれぞれについて、仮数の2^52値があります。さらに、指数が0x000の場合、仮数はその先行値なしで解釈されますが、指数が0x001であるかのように、合計0x3FF = 1023の指数であり、すべての仮数が有効です。これは合計1023*2^52の値です。さらに、負の0がカウントされる場合があります。これは、もう1つの値です。

ランダムなdoubleがすべての値から均一に生成された場合、Int64を生成するために乗算すると、実際にバイアスが発生します。ただし、妥当なランダムライブラリは[0、1)で一様分布に近似し、これをInt64に変換するときにバイアスがかかることはありません。[0、big)のすべての整数を生成できる「big」の最大値は2 ^53です。1/2から1までの2^52の数値の解像度は2^(-53)です。ただし、これらの数値は、乱数を整数範囲(通常はInt32)で除算することによって生成されることがよくあります。つまり、実際には、このソースより多くの数値を生成することはできません。代わりに、2つのInt32を直接結合することを検討してください。たとえば、1つずつ32ビットシフトし、それらをInt64に結合します。(注意が必要ですが、ジェネレーターの状態空間は32ビットしかない場合があります。)

于 2011-03-18T10:58:44.987 に答える
5

あなたの質問の当然の結果として、RandomC#ジェネレーターは、内部での間の数値を「与える」ジェネレーターを使用していることをお伝えします0...Int32.MaxValue - 1。次に、数値をInt32.MaxValue(技術的にはその数値の逆数で乗算して)除算して、doubleを返します。Int32.MaxValueしたがって、C#では、返される可能性のあるdoubleのみがあります( 0...Int32.MaxValue - 1

于 2011-03-18T09:58:15.643 に答える
3

IEEE754は、doubleの精度についてかなり明確です。

http://en.wikipedia.org/wiki/IEEE_754-2008

52ビットの精度と追加の想定ビットがあります。

-1022から1023までの指数があり、符号を含めて約11ビットです。

64番目のビットは、数値の全体的な符号です。

正規化されていない数値は無視します。

-1022から0までの指数について質問しています。これは、使用可能な11ビットの指数のうち約10が使用可能であることを意味します。

52+1ビットの仮数が使用可能です。

これは、2**62の異なる値を表すために使用できる約62ビットの精度です。

ここに画像の説明を入力してください

于 2011-03-18T11:08:39.233 に答える
1

@wnoiseはほとんどそれを釘付けにしました、しかしここに私の2セントがあります。

IEEEフロートは、いくつかの制限付きで整数として比較およびインクリメントできます。詳細については、この質問を参照してください。したがって、+ 0.0および1.0から64ビットの整数をキャストすると、0から1までのステップ数が得られます。

#include <iostream>

int main()
{
        double zero = 0.0;
        double one = 1.0;
        unsigned long long z = *reinterpret_cast<unsigned long long*>(&zero);
        unsigned long long o = *reinterpret_cast<unsigned long long*>(&one);
        std::cout << z << std::endl;
        std::cout << o << std::endl;
}

これにより、それぞれ0と4607182418800017408が得られます。つまり、[0.0、1.0)の範囲に4607182418800017408の一意のdouble値があります。

于 2011-03-18T11:39:24.943 に答える
0

double[0.0、1.0)の範囲内のaの一意の値の総数doubleは、特定の環境でのの表現によって異なります。

最も一般的な表現の1つは、IEEE754で指定されている表現です。この形式は、たとえばJavaC#で義務付けられています(後者については1.3タイプと変数を参照してください)。

于 2011-03-18T09:47:55.523 に答える
0

これは、の実装によって異なりますdouble。非正規化された値を許可せず、先頭の値を除外する実装があります。ここで可能な値の数を決定するのは簡単です。

  • いくつかの「特別な」値(0、+ 0、-0、+∞、-∞、サイレントNaN、シグナリングNaN)があり、通常は1つの可能な指数が必要です。
  • 仮数をシフトして指数を変更すると、同等の数値が得られる方法はありません。

実装で非正規化された値が許可されている場合、この数値を決定するのは少し難しくなりますが、この表現で可能な値を、先頭が固定された同等の表現(仮数で使用する値が1ビット少なくなります)にマッピングすることから始めます。適切なマッピングを見つけた場合、これは単射であり、問​​題をより単純なものに減らしました。

于 2011-03-18T10:09:00.460 に答える