awk 的 rand() 可以給你多少小數位?
rand() 將給出多少個小數位?
我假設 rand() 值不能是從 0 到不包括 1 的任何完全任意的數字,並且它僅限於一定數量的小數位或類似的東西。它是基於作業系統還是存在 X 小數位的隨機限制。
同樣,我想知道: rand() 有多精確?
帶走
除了下面詳細解釋的浮點限制(不超過 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()
(readsupport/random.c
) 返回 31 位,儘管內置了任意精度的數學。仍然多於 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
你會發現有 53 個十進制數字(至少在 Linux GNU 中)。
為什麼是 53?
這與用於在 awk 中表示數字的二進制浮點數尾數中使用的二進制位數完全相同。好吧,至少使用IEEE 754 定義的“雙精度”浮點數(8 字節浮點數)
問:是這個原因嗎?二進制位數是否等於十進制位數?
A:一句話:是的。
證明
任何二進制分數,即一個零後跟一個點,後跟幾個二進制數字:
0.100110011
可以寫成:
a1×2-1 + a2×2-2 + a3×2-3 + ….
對於某個i二進制數字的序列。
例如:
0.100110011
1×2-1 + 0×2-2 + 0×2-3 + 1×2-4 + 1×2-5 + ….
刪除零:
2-1 + 2-4 + 2-5 + 2-8 + 2-9
分解出 2 -9:
( 2+8 + 2+5 + 2+4 + 21 + 1 ) × 2-9
括號內是一個整數二進制數:
100110011 #(十進制307)
這個分數實際上是一個二進制分數:
307 × 2-9
307 / 29
如果我們將分子和分母都乘以 5 9我們得到:
307 × 59 / 29 × 59
307 × 59 / 109
307 × 1953125 / 109
599609375 / 109
0.599609375
與二進制小數位數相同的十進制小數。
因此,所有二進制分數都可以(完全)轉換為點後完全相同位數的十進制分數(分母的指數相同)。反過來是不正確的。並非所有小數都可以轉換為二進制小數。
現在我們知道怎麼做:我們可以嘗試更長的分數:
0.10011001100110011001100110011001100110011001100110011
100110011001100110011001100110011001100110011001100112 / 253
540431955284459510 / 253
540431955284459510 × 553 / 1053
5404319552844595 × 11102230246251565404236316680908203125 / 1053
59999999999999997779553950749686919152736663818359375 / 1053
0.59999999999999997779553950749686919152736663818359375
這正是 awk
0.6
在 53 位中給出的表示:$ awk 'BEGIN{printf("%.60g\n",0.6)}' 0.59999999999999997779553950749686919152736663818359375
因此,53 位十進制數字是 awk 可以使用 53 位尾數的浮點數給出的最大值。
好吧,將其讀取為 53 個有效數字,因為某些數字可能有前導零:
$ awk 'BEGIN{printf("%.90f\n",3^-20)}' 0.000000000286797199079244134930566254988964884631297280748185585252940654754638671875000000
免費數字。
問:但是所有浮點數(小數部分)都以 5 結尾,是否有某種潛在的力量使數字不隨機?
答:是的。
描述
任何二進制數字都有十進制的精確表示。如上所述,二進制分數是:
a1×2-1 + a2×2-2 + a3×2-3 + ….
對於 a i的一些序列。每個指數的值是完全已知的:
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.00390625
2-9 = 0.001953125
2-10 = 0.0009765625
…
我們可以看到為什麼以及如何用連續的二進制分數來近似像 0.6 這樣的數字。
添加的每個連續分數都必須來自下方。所有分數都被添加,沒有辦法回到更小的值。
2 -1 = 0.5 ==> 0.5
第一個二進制數字貢獻 0.5,我們距離 0.6 有 0.1。下一個:0.25 和後面的 0.125 比需要添加的要大。因此,它們無法使用。接下來的兩個可以添加。第一個 2 -4 (0.0625) 小於 0.1 的差值,可以添加。第二個 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 個二進制數字,並且根據上面的結果,已經生成了 21 個十進制數字。但那些數字不是免費的。它們與前 6 位十進制數字的值相關聯。
但是,試圖從特定範例中生成一般規則是不可能的。
一般來說:
使用更高級別的數學,我們可以說:
問:對於截斷的位數,有多少十進制數字是“有效的”?
答:2^(b-1) >= 10^d - 1
這是他 1967 年論文中的 Matula 公式:D._W。Matula, “Base_conversion_mappings”,_1967_Spring_Joint_Computer_Conf.,_AFIPS_Proc.,_vol._30.,_pp._311-318
應用於十進制數字 (d) 轉換為二進制數字 (b)
正如我們通常知道一個浮點數能夠儲存多少二進制位一樣,我們可以求解 d(通過 b 個二進制數字往返的十進制數字):
2^(b-1) >= 10^d - 1 # 使用
>
唯一(去掉 - 1)2^(b-1) > 10^d # 應用 log
log 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
如上所示,21 個二進制位生成 0.599999904632568359375,但只有 6 個(四捨五入)數字是可信的。0.599999 必須四捨五入到 0.6,因為下一位是 9。
所以:0.6 往返二進制並再次變為 0.6。
使用 21 個二進制位:可靠地轉換多達 6 個十進制數字。
最終的
rand
那麼,可以生成多少(有效)數字:使用的浮點數可以從二進制轉換回來。(使用上表)。
對於 53 位二進製文件,最多可以信任 15 位數字。
採用:
$ awk -M -vPREC=101 'BEGIN{printf("%.33g\n",0.6)}' 0.599999999999999999999999999999921
如果您需要至少 30 個浮點數的十進制數字。
但是還有其他限制問題,例如 LFSR 程式碼中使用的位數。這是此答案開頭提到的限制。