無料番号。

無料番号。

rand()は小数点以下の数桁を提供しますか?

私は、rand()の値が0から1を含まない任意の数値にすることはできず、特定の小数点以下の数に制限されると仮定します。オペレーティングシステムに基づいていますか、それとも少数のX桁までランダムな制限がありますか?

同様に、私は知りたいです:rand()はどれほど正確ですか?

答え1

奪う

以下に詳述する浮動小数点制限(10進数15桁以下)に加えて、ソースコードには次の追加制限があります。

もともとawkは以下に制限されていました。ただrand()関数には32768(0..32767)の異なる値があります。

/* #ifndef RAND_MAX */  
/* #define RAND_MAX     32767 */        /* all that ansi guarantees */  
/* #endif */

これは4桁以上の数字です。これは古いawkで信頼できるすべてです。

mawkの実装には、rand()に対する16ビットから32ビット(0..4294967295)の範囲のいくつかの制限があります。したがって、9桁が少し以上です。

奇妙なことに、GNU awkは組み込みの任意精度の数学にもかかわらずrandom()(読み取り)31ビットだけを返します。support/random.cそれでも9桁以上ですが、mawk arc4random(BSDから)(0..2147483647)の半分です。


awkの浮動小数点表現を段階的に見てみましょう。

rand()は小数点以下の数桁を提供しますか?

明らか

明らかな答えは次のとおりです。どのくらいの時間が必要ですか(例:ほとんどのバージョン):

$ awk 'BEGIN{srand(11); printf("%.83f\n",rand())}'
0.37904318086255550657170942940865643322467803955078125000000000000000000000000000000

srand(11)反復可能な乱数を生成するために使用されます。すべてのユーザーは同じ乱数を受け取る必要があります(GNU awkではawkのバージョンによって異なりますが、反復呼び出しとシステムでは安定しています)。

はい、83より多くの桁がある可能性があり、多くの桁が忠実に印刷されます。

しかし、数回数えた後は、どんなに多くの数字を要求しても、すべての数字がゼロになることは明らかです。

効果的な

数を数えるには:

$ printf '%s' "  " $(seq 9)"_"{,,,,,}; echo; \
    awk 'BEGIN{srand(11); printf("%.63f\n",rand())}';\
    printf '  ';printf '^%.0s' $(seq 53); echo "<--- up to here"

  123456789_123456789_123456789_123456789_123456789_123456789_
0.379043180862555506571709429408656433224678039550781250000000000
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<--- up to here

10進数は53桁です(少なくともLinux GNUでは)。

なぜ53ですか?

これは、awkで数値を表すためにバイナリ浮動小数点数の仮数に使用されるバイナリ数の数とまったく同じです。まあ、少なくとも「二重精度」浮動小数点数(8バイト浮動小数点数)IEEE 754で定義

Q:これが理由ですか? 2進数は10進数と同じですか?

A:簡単に言えばそうです。

証明する

どのバイナリ噴水つまり、ゼロの後に点が続き、その後にいくつかの2進数が続きます。

0.100110011

次のように書くことができます:

1×2 -1 + 2 × 2 -2 + 3 ×2 -3 + ....

特定のi番目の2進数シーケンスの場合。

たとえば、

0.100110011
1×2 -1 + 0×2 -2 + 0×2 -3 + 1×2 -4 + 1×2 -5 + ....

0を削除します。

2-1 + 2-4 + 2-5 + 2-8 + 2-9

2-9因数分解:

(2 +8 + 2 +5 + 2 +4 + 2 1 + 1)×2 -9

括弧内には整数の二進数があります。

100110011#(10進数307)

この分数は実際にはバイナリ分数です。

307× 2 -9307/2 9

分子と分母に 5 9 を掛けると次のようになります。

307×5 9/2 9 ×5 9307 ×5 9/10 9307 × 1953125 /10 9 599609375/10 9 0.599609375



2進数と桁数が等しい10進分数。

したがって、すべてのバイナリ分数を変換できます(正確に)を点の後の桁数が正確に同じ小数点で表示します(分母の指数は同じです)。その逆は真実ではありません。すべての素数をバイナリ分数に変換できるわけではありません。

今、私たちは何をするのか分かりました:より長い噴水を試すことができます:

0.10011001100110011001100110011001100110011001100110011
100110011001100110011001100110011001100110011001100112 / 253
540431955284459510 / 253
540431955284459510 × 553 / 1053
5404319552844595 × 11102230246251565404236316680908203125 / 1053
59999999999999997779553950749686919152736663818359375 / 1053
0.59999999999999997779553950749686919152736663818359375

これはawkが提供する0.653ビット表現とまったく同じです。

$ awk 'BEGIN{printf("%.60g\n",0.6)}'
0.59999999999999997779553950749686919152736663818359375

したがって、10進数53桁は、awkが提供できる最大53桁の仮数浮動小数点数です。

まあ、53で発音されます重要数字(一部の数字は前にゼロが続くことがあります):

$ awk 'BEGIN{printf("%.90f\n",3^-20)}'
0.000000000286797199079244134930566254988964884631297280748185585252940654754638671875000000

無料番号。

Q:しかし、すべての浮動小数点数(10進数)は5で終わります。数字をランダムではないものにする基本的な力はありますか?

答え:はい。

説明する

すべての2進数は正確な10進数表現を持ちます。上記のように、バイナリの分数は次のとおりです。

1×2 -1 + 2 × 2 -2 + 3 ×2 -3 + ....

特定のシーケンスのaiについて。各インデックスの値はよく知られています。

2 -1 = 0.5 2
-2 = 0.25 2
-3 = 0.125
2 -4 = 0.0625
2 -5 = 0.03125
2 -6 = 0.015625
2 -7 = 0.0078125
2 -8 = 0.00309 0.0009765625 ...


0.6などの数字が連続した2進数に近似できる理由と方法がわかります。
追加された各連続スコアは、以下から来なければなりません。次のような。すべての分数は一緒に追加され、小さい値に戻る方法はありません。

2 -1 = 0.5 ==> 0.5

最初の2進数は0.5に貢献し、0.6から0.1だけ離れています。次へ:0.25と0.125以降は追加する必要があります。したがって、使用できません。次の 2 つを追加できます。最初の2〜4 0.0625)は0.1未満の違いなので、追加できます。 2番目の2 -5(0.03125)は、最初の違いである0.375より小さく、追加することもできます。

2<sup>-1</sup>   = 0.5                     ==> 0.5
2<sup>-4</sup>   = 0.0625                  ==> 0.5625
2<sup>-5</sup>   = 0.03125                 ==> 0.59375
----------------------^ <== digit being approximated
-----------------------*** <== trailing digits of each fraction.

各連続バイナリビットが0.6表現に追加されると、結果はその値に近づきます。

2<sup>-8</sup>   = 0.00390625              ==> 0.59765625
2<sup>-9</sup>   = 0.001953125             ==> 0.599609375

2<sup>-12</sup>  = 0.000244140625          ==> 0.599853515625
2<sup>-13</sup>  = 0.0001220703125         ==> 0.5999755859375

2<sup>-16</sup>  = 0.0000152587890625      ==> 0.5999908447265625
2<sup>-17</sup>  = 0.00000762939453125     ==> 0.59999847412109375

2<sup>-20</sup>  = 0.00000095367431640625  ==> 0.59999942779541015625
2<sup>-21</sup>  = 0.000000476837158203125 ==> 0.599999904632568359375    
digit being approximated-------------------------------| <==
Accumulated trailing digits. ---------------------------^^^^^^^^^^^^^^ 

そのため、最初の6桁を設定するときに21桁の2進数を使用し、上記の結果に基づいて21個の10進数を生成しました。しかし、この数字は無料ではありません。これは、小数点の最初の6桁の値に関連しています。

しかし、具体的なケースから一般的なルールを作成することは不可能です。

一般的に言うと:

より高いレベルの数学を使用すると、次のように話すことができます。

Q: 切り捨てられた数字に対して「有効な」10 進数は何ですか?

答え: 2^(b-1) >= 10^d - 1

これは彼の1967年の論文D._WのMatulaの公式です。マチュラ、「Base_conversion_mappings」、_1967_Spring_Joint_Computer_Conf.、_AFIPS_Proc.、_vol._30.、_pp._311-318

10進数に適用(d) 2進数に変換(b)

通常、浮動小数点数がどのように2進数を格納できるかを知っているので、d(10進からbの2進数の往復)を解くことができます。

2^(b-1) >= 10^d - 1 #>一意のエントリの使用(remove - 1)
2^(b-1) > 10^d # アプリケーション
ログログ10 (2) × (b-1) >d

したがって(最大整数):

d = int( log 10 (2) × (b-1) )
d = int( 0.30102999566 * (b-1) ) # 十分に閉じます。

 Bits  5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 65 69 73 77 81 85 89 93 97 101 105 109 113  
digits 1 2  3  4  6  7  8  9 10 12 13 14 15 16 18 19 20 21 22 24 25 26 27 28  30  31  32  33

上記のように、2進数の21桁は0.599999904632568359375を生成しますが、丸められた6桁だけが信頼できます。 0.599999は次の数字が9であるため、0.6に丸める必要があります。

したがって、0.6はバイナリを往復し、再び0.6になります。
21個の2進数:最大6個の10進数まで安定して変換できます。

決定的な

したがって、どのくらい(有効な)数を生成できますかrand

使用される浮動小数点数は、バイナリから可能な限り多くの浮動小数点数に戻すことができます。 (上記の表を使用してください)。

53ビットバイナリの場合、15桁以下しか信頼できません。

使用:

$ awk -M -vPREC=101 'BEGIN{printf("%.33g\n",0.6)}'
0.599999999999999999999999999999921

小数点以下30桁以上のために浮動小数点数が必要な場合。

ただし、LFSR コードに使用されるビット数などの他の制限もあります。これがこの回答の冒頭に記載されている制限です。

答え2

私はGNU Awk 4.1.3、API:1.1(GNU MPFR 3.1.4、GNU MP 6.1.0)を使用しています。

10桁まで正確な乱数百万個を生成し、999744個の固有値を得ました。価値観は私が見ているものをブロックしません。しかし、高い値が低い値よりも多くコピーされ、低い値が増加するよりも減少する速度が速いようで、分布が線形かどうかはわかりません。

Paul--) echo 1000000 | 
> awk 'BEGIN { srand();}
> { for (j = 0; j < $1; j++) 
>   printf ("%12.10f\n", rand()); }' > foo.rand
Paul--) wc foo.rand
 1000000  1000000 13000000 foo.rand
Paul--) sort foo.rand | uniq | wc -l
999744
Paul--) sort foo.rand | uniq -c | sort -n | head -n 5
  1 0.0000011418
  1 0.0000023860
  1 0.0000025611
  1 0.0000035479
  1 0.0000037365
Paul--) sort foo.rand | uniq -c | sort -nr | head -n 5
  2 0.9966602395
  2 0.9950194126
  2 0.9909849539
  2 0.9852069067
  2 0.9822554230

関連情報