Awk

awk 的 rand() 可以給你多少小數位?

  • February 5, 2020

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()(read support/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

這正是 awk0.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 程式碼中使用的位數。這是此答案開頭提到的限制。

引用自:https://unix.stackexchange.com/questions/565183