rand()는 소수점 이하 몇 자리를 제공합니까?
나는 rand() 값이 0에서 1을 포함하지 않는 임의의 숫자일 수 없으며 특정 소수 자릿수 또는 이와 유사한 것으로 제한된다고 가정합니다. 운영 체제를 기반으로 합니까, 아니면 소수 X자리까지 임의 제한이 있습니까?
마찬가지로, 나는 알고 싶습니다: rand()는 얼마나 정확합니까?
답변1
빼앗다
아래에 자세히 설명된 부동 소수점 제한 사항(십진수 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 ) 에서 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보다 더 많은 자릿수가 있을 수 있으며 그 많은 자릿수가 충실하게 인쇄됩니다.
하지만 몇 번 세어본 후에는 아무리 많은 숫자를 요청하더라도 모든 숫자가 0이 될 것임이 분명합니다.
효과적인
개수를 계산하려면 다음을 수행하세요.
$ 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에서 숫자를 표현하기 위해 이진 부동 소수점 숫자의 가수에 사용되는 이진 숫자의 수와 정확히 같습니다. 글쎄, 적어도"이중 정밀도" 부동 소수점 숫자(8바이트 부동 소수점 숫자)는IEEE 754에 의해 정의됨
질문: 이것이 이유인가요? 이진수는 십진수와 같나요?
A: 간단히 말해서 그렇습니다.
입증하다
어느이진 분수, 즉 0 다음에 점이 오고 그 뒤에 몇 개의 이진수가 옵니다.
0.100110011
다음과 같이 쓸 수 있습니다:
1 × 2 -1 + 2 × 2 -2 + 3 × 2 -3 + ....
특정 i 번째 이진수 시퀀스의 경우.
예를 들어:
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 #(십진수 307)
이 분수는 실제로 이진 분수입니다.
307 × 2 -9
307 / 2 9
분자와 분모에 5 9를 곱하면 다음과 같습니다.
307×5 9/2 9 × 5 9
307×5 9/10 9 307
×1953125/10 9
599609375/10 9 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
따라서 10진수 53자리는 awk가 제공할 수 있는 최대 53자리 가수 부동 소수점 숫자입니다.
음, 53으로 발음됩니다중요한숫자(일부 숫자에는 앞에 0이 올 수 있음):
$ awk 'BEGIN{printf("%.90f\n",3^-20)}'
0.000000000286797199079244134930566254988964884631297280748185585252940654754638671875000000
무료 번호.
Q: 하지만 모든 부동 소수점 숫자(십진수)는 5로 끝납니다. 숫자를 무작위가 아닌 것으로 만드는 근본적인 힘이 있나요?
대답: 그렇습니다.
설명하다
모든 이진수는 정확한 십진수 표현을 갖습니다. 위에서 언급했듯이 이진 분수는 다음과 같습니다.
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.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자리의 값과 관련이 있습니다.
그러나 구체적인 사례로부터 일반적인 규칙을 생성하는 것은 불가능합니다.
일반적으로 말하면:
더 높은 수준의 수학을 사용하면 다음과 같이 말할 수 있습니다.
Q: 잘린 숫자에 대해 "유효한" 십진수는 몇 개입니까?
답: 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)
우리는 일반적으로 부동 소수점 숫자가 몇 개의 이진수를 저장할 수 있는지 알고 있으므로 d(십진수에서 b 이진수의 왕복)를 풀 수 있습니다.
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
위와 같이 이진수 21자리는 0.599999904632568359375를 생성하지만, 반올림된 6자리만 신뢰할 수 있습니다. 0.599999는 다음 숫자가 9이므로 0.6으로 반올림해야 합니다.
따라서 0.6은 바이너리를 왕복하고 다시 0.6이 됩니다.
21개의 이진수: 최대 6개의 십진수까지 안정적으로 변환할 수 있습니다.
결정적인
따라서 얼마나 많은 (유효한) 숫자가 생성될 수 있습니까 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