bash에서 크고 균일하게 분포 된 임의의 정수를 효율적으로 생성하는 방법은 무엇입니까?


30

내가 얻을 수있는 가장 좋은 방법이 될 것 궁금 된 좋은 절차 사이에 임의의 양의 정수를 얻을 수있을 것입니다 무슨 즉 bash는,의 임의성을 MIN하고 MAX있도록

  1. 범위는 임의로 클 수있다 (또는 적어도 2 32 -1까지).
  2. 값은 균일하게 분포됩니다 (즉, 편견 없음).
  3. 효율적입니다.

bash에서 임의성을 얻는 효율적인 방법은 $RANDOM변수 를 사용하는 것 입니다. 그러나이 값은 0과 2 15 -1 사이의 값만 샘플링하므로 모든 용도에 충분하지 않을 수 있습니다. 사람들은 일반적으로 모듈러스를 사용하여 원하는 범위로 가져옵니다.

MIN=0
MAX=12345
rnd=$(( $RANDOM % ($MAX + 1 - $MIN) + $MIN ))

또한 $MAX2 15 -1 = 32767 을 나누지 않는 한 편향이 발생합니다 . 예, 경우 $MIN0이고 $MAX로, 다음 7을 통해 값 0이 약간 값 8 및 9보다 더 가능성이 있으며, 9입니다 $RANDOM없을 것 32768 또는 32769. 경우 바이어스, 예를 들어, 범위 증가로 악화 $MIN0이고 $MAX있다 9999 후 2,767 내지 번호 0의 확률이 4 / 32767 9999 수가 2,768 만 확률이 동안 3 / 32767 .

따라서 위의 방법은 조건 3을 충족하지만 조건 1과 2를 충족 시키지는 않습니다.

조건 1과 2를 만족 시키려고 지금까지 생각해 낸 가장 좋은 방법 /dev/urandom은 다음과 같이 사용 하는 것입니다.

MIN=0
MAX=1234567890
while
  rnd=$(cat /dev/urandom | tr -dc 0-9 | fold -w${#MAX} | head -1 | sed 's/^0*//;')
  [ -z $rnd ] && rnd=0
  (( $rnd < $MIN || $rnd > $MAX ))
do :
done

기본적으로,에서 불과 수집 임의성 /dev/urandom(사용 고려해 볼 수 있습니다 /dev/random강력한 암호 의사 난수 생성기가 필요한 경우 대신, 당신이있는 경우에 많은 다른 어쩌면 하드웨어 난수 발생기 시간, 또는), 진수 숫자 아니라 모든 문자를 삭제, 배 출력을 $MAX선행 0의 길이로 자르십시오. 우리가 0을 얻는다면 $rnd비어 있습니다. 이 경우에는로 설정 rnd하십시오 0. 결과가 범위를 벗어 났는지 확인하고, 그렇다면 범위를 반복하십시오. 나는 모방의 정신, 한 번에 적어도 몸의 힘 실행을 않도록 여기에 가드로 While 루프의 "몸"을 강제 do ... while하기 때문에, 루프를 rnd시작하는 정의되지 않는다.

나는 여기에서 조건 1과 2를 충족했다고 생각하지만 지금은 조건 3을 망쳤습니다. 다소 느립니다. 운이 좋으면 1 초 정도 걸립니다 (1/10 초). 실제로 루프가 종료되는 것은 보장되지 않습니다 (시간이 증가함에 따라 종료 확률은 1로 수렴하지만).

bash에서 미리 지정되고 잠재적으로 넓은 범위 내에서 바이어스되지 않은 임의의 정수를 얻는 효율적인 방법이 있습니까? (시간이 허락되면 계속 조사 할 것이지만 그 동안 여기 누군가 멋진 아이디어가 있다고 생각했습니다!)

답변 표

  1. 가장 기본적인 (따라서 휴대용) 아이디어는 충분히 긴 임의의 비트 열을 생성하는 것입니다. bash의 내장 $RANDOM변수를 사용하거나 odand 및 /dev/urandom(또는 /dev/random)를 사용 하여 임의의 비트 문자열을 생성하는 방법에는 여러 가지가 있습니다 . 난수가보다 큰 경우 $MAX다시 시작하십시오.

  2. 또는 외부 도구를 사용할 수도 있습니다.

    • 펄 솔루션
      • 프로 : 휴대 성이 뛰어나고 단순하며 유연합니다
      • 대조 : 2 32 -1 이상의 매우 큰 숫자에는 해당되지 않음
    • 파이썬 솔루션
      • Pro : 단순하고 유연하며 많은 수의 사람들에게도 효과가 있습니다.
      • 대조 : 휴대 성이 떨어짐
    • zsh 솔루션
      • Pro : 어쨌든 zsh를 사용하는 사람들에게 좋습니다
      • 대조 : 아마도 휴대 성이 떨어짐

임의의 비트를 base64로 인코딩하는 대신 정수만 선택하여 인코딩 된 형식에서 base64의 base10으로 특정 수의 문자 (필요한 범위에 따라 다름)를 변환하는 이유는 무엇입니까?
muru

그것은 않습니다 필요 배쉬로? 하고 싶은 무언가 rand=$(command)경우 어떻게 command반환 요구 사항을 다하는 iteger?
terdon

@muru 실제로 좋은 생각입니다. 내가 사용, 유사한 아이디어에 대한 몇 가지 생각을 보냈다 dd if=/dev/urandom 2>/dev/null과를 통해 그 배관 od -t d(64 기수를 통해 우회 방지), 그러나 변환이 발생하고 실제로 편견인지 어떻게 나에게 분명하지 않다. 아이디어를 효율적이고 효과적인 스크립트로 확장하고 편견이없는 이유를 설명 할 수 있다면 큰 대답이 될 것입니다. :)
Malte Skoruppa

@ terdon 나는 bash를 선호한다. 물론 당신이 호출 할 수의 내 말은, python또는 perl당신의 마음에 드는 언어를하거나,하지만이 모든 곳에서 사용할 수 없습니다. 좀 더 휴대하기 좋은 것을 선호합니다. 글쎄, awk의 임의의 기능은 괜찮을 것입니다. 그러나 휴대 성이 좋을수록 더 좋습니다 :)
Malte Skoruppa

2
그렇습니다 perl -e 'print int(rand(2**32-1))');. 그것은 꽤 대담한 휴대용이며 매우 빠를 것입니다. 대부분의 구현은 동일한 시드에서 시작하기 때문에 Awk는 잘리지 않습니다. 따라서 후속 실행에서 동일한 난수를 얻습니다. 동일한 실행 내에서만 변경됩니다.
terdon

답변:


17

나는 여기서 또 다른 흥미로운 방법을 본다 .

rand=$(openssl rand 4 | od -DAn)

이것은 또한 좋은 옵션 인 것 같습니다. 그것은 임의의 장치로부터의 4 바이트를 판독하고, 부호없는 정수로 사이를 포맷 0하고 2^32-1.

rand=$(od -N 4 -t uL -An /dev/urandom | tr -d " ")


od명령이 다른가? 둘 다 4 바이트 부호없는 정수를 인쇄합니다 : 1st-from openssl, 2nd-from /dev/random.
jfs

1
@Ramesh /dev/urandom대신 사용하도록 편집했습니다 /dev/random-사용할 이유가 없으며 /dev/random실제로 비싸거나 느리거나 시스템의 다른 부분을 느리게 할 수 있습니다. (무료로 편집
해보고

1
걱정할 필요는 없습니다.이 단순한 차이가 너무 복잡한 영향을 미친다는 것은 놀라운 일입니다. 그래서 나는 사람들이 예제를 통해 배우는 예제를 올바른 것으로 바꾸라고 주장했습니다.
Volker Siegel

1
@MalteSkoruppa는 : I의미 sizeof(int)그 이하로 할 수있다 4원칙이다. btw는 od -DAn실패 (2**32-1)하지만 od -N4 -tu4 -An계속 작동합니다.
jfs

8

모든 훌륭한 답변에 감사드립니다. 나는 다음과 같은 해결책으로 끝내고 싶다.

이유와 방법에 대해 더 자세히 설명하기 전에 여기에 tl; dr : 반짝이는 새 스크립트가 있습니다 :-)

#!/usr/bin/env bash
#
# Generates a random integer in a given range

# computes the ceiling of log2
# i.e., for parameter x returns the lowest integer l such that 2**l >= x
log2() {
  local x=$1 n=1 l=0
  while (( x>n && n>0 ))
  do
    let n*=2 l++
  done
  echo $l
}

# uses $RANDOM to generate an n-bit random bitstring uniformly at random
#  (if we assume $RANDOM is uniformly distributed)
# takes the length n of the bitstring as parameter, n can be up to 60 bits
get_n_rand_bits() {
  local n=$1 rnd=$RANDOM rnd_bitlen=15
  while (( rnd_bitlen < n ))
  do
    rnd=$(( rnd<<15|$RANDOM ))
    let rnd_bitlen+=15
  done
  echo $(( rnd>>(rnd_bitlen-n) ))
}

# alternative implementation of get_n_rand_bits:
# uses /dev/urandom to generate an n-bit random bitstring uniformly at random
#  (if we assume /dev/urandom is uniformly distributed)
# takes the length n of the bitstring as parameter, n can be up to 56 bits
get_n_rand_bits_alt() {
  local n=$1
  local nb_bytes=$(( (n+7)/8 ))
  local rnd=$(od --read-bytes=$nb_bytes --address-radix=n --format=uL /dev/urandom | tr --delete " ")
  echo $(( rnd>>(nb_bytes*8-n) ))
}

# for parameter max, generates an integer in the range {0..max} uniformly at random
# max can be an arbitrary integer, needs not be a power of 2
rand() {
  local rnd max=$1
  # get number of bits needed to represent $max
  local bitlen=$(log2 $((max+1)))
  while
    # could use get_n_rand_bits_alt instead if /dev/urandom is preferred over $RANDOM
    rnd=$(get_n_rand_bits $bitlen)
    (( rnd > max ))
  do :
  done
  echo $rnd
}

# MAIN SCRIPT

# check number of parameters
if (( $# != 1 && $# != 2 ))
then
  cat <<EOF 1>&2
Usage: $(basename $0) [min] max

Returns an integer distributed uniformly at random in the range {min..max}
min defaults to 0
(max - min) can be up to 2**60-1  
EOF
  exit 1
fi

# If we have one parameter, set min to 0 and max to $1
# If we have two parameters, set min to $1 and max to $2
max=0
while (( $# > 0 ))
do
  min=$max
  max=$1
  shift
done

# ensure that min <= max
if (( min > max ))
then
  echo "$(basename $0): error: min is greater than max" 1>&2
  exit 1
fi

# need absolute value of diff since min (and also max) may be negative
diff=$((max-min)) && diff=${diff#-}

echo $(( $(rand $diff) + min ))

그것을 저장 ~/bin/rand하면 주어진 임의의 범위에서 정수를 샘플링 할 수있는 bash의 달콤한 임의 함수를 사용할 수 있습니다. 범위는 음의 정수와 양의 정수를 포함 할 수 있으며 최대 길이는 2 60 -1입니다.

$ rand 
Usage: rand [min] max

Returns an integer distributed uniformly at random in the range {min..max}
min defaults to 0
(max - min) can be up to 2**60-1  
$ rand 1 10
9
$ rand -43543 -124
-15757
$ rand -3 3
1
$ for i in {0..9}; do rand $((2**60-1)); done
777148045699177620
456074454250332606
95080022501817128
993412753202315192
527158971491831964
336543936737015986
1034537273675883580
127413814010621078
758532158881427336
924637728863691573

다른 응답자의 모든 아이디어는 훌륭했습니다. terdon , JF Sebastianjimmij 의 답변은 외부 도구를 사용하여 간단하고 효율적인 방식으로 작업을 수행했습니다. 그러나, 나는 최대한의 이식성을 위해 진정한 bash 솔루션을 선호했으며, 아마도 bash에 대한 사랑에서 조금 벗어나는 것이 좋았습니다.)

Rameshl0b0 의 답변이 사용 /dev/urandom되거나 /dev/random함께 사용 됩니다 od. 그러나이 방법은 바이트 수, 즉 길이 8의 비트 열을 샘플링하기 때문에 일부 n에 대해 0에서 2 8n -1 범위의 난수 만 샘플링 할 수 있다는 단점이있었습니다. n 증가

마지막으로 Falco 의 답변은 임의의 범위 (2의 거듭 제곱이 아닌)에 대해 어떻게 수행 할 수 있는지에 대한 일반적인 아이디어를 설명합니다 . 기본적으로 주어진 범위 {0..max}에 대해 다음 2의 거듭 제곱이 무엇인지, 즉 비트 열로 표현하는 데 필요한 비트 수를 정확하게 결정할 수 있습니다 max. 그런 다음이 비트 수를 샘플링하여이 바이 스트링이 정수보다 큰지 확인할 수 max있습니다. 그렇다면 반복하십시오. 를 나타내는 데 필요한만큼의 비트를 샘플링하기 때문에 max각 반복의 성공 확률은 성공률의 50 %보다 크거나 같습니다 (최악의 경우 50 %, 가장 좋은 경우 100 %). 따라서 이것은 매우 효율적입니다.

필자의 스크립트는 기본적으로 순수 bash로 작성되고 bash의 내장 비트 연산을 사용하여 원하는 길이의 비트 문자열을 샘플링하기 때문에 Falco의 답변을 구체적으로 구현합니다. Eliah Kagan 의 아이디어는 또한 $RANDOM반복적으로 호출하여 발생하는 비트 스트링을 연결 하여 내장 변수 를 사용하도록 제안합니다 $RANDOM. 나는 실제로 사용할 수있는 가능성을 모두 구현 /dev/urandom$RANDOM. 기본적으로 위 스크립트는을 사용합니다 $RANDOM. (그리고 괜찮다면 odtr이/dev/urandom 필요 하지만 POSIX가 지원합니다.)

어떻게 작동합니까?

이것에 들어가기 전에 두 가지 관찰이 있습니다.

  1. bash는 2 63 -1 보다 큰 정수를 처리 할 수 ​​없습니다 . 직접 참조하십시오 :

    $ echo $((2**63-1))
    9223372036854775807
    $ echo $((2**63))
    -9223372036854775808

    bash는 내부적으로 부호있는 64 비트 정수를 사용하여 정수를 저장하는 것으로 보입니다. 따라서 2 63 에서 "포장"하고 음의 정수를 얻습니다. 따라서 우리는 우리가 사용하는 임의의 함수로 2 63 -1 보다 큰 범위를 갖기를 희망하지 않습니다 . 배쉬는 단순히 그것을 처리 할 수 ​​없습니다.

  2. 우리 사이의 임의의 범위의 값 샘플링 할 때마다 minmax가능성과를 min != 0, 우리는 단순히 사이의 값을 샘플링 할 수 0max-min대신하고 추가 min최종 결과에. 이 경우에도 작동 min및 가능성도 max있다 ,하지만 우리 사이의 값 샘플링주의해야 0의 절대 값을 max-min . 따라서 0임의의 양의 정수 사이의 임의의 값을 샘플링하는 방법에 중점을 둘 수 있습니다 max. 나머지는 쉽습니다.

1 단계 : 정수 (로그)를 나타내는 데 필요한 비트 수 결정

따라서 주어진 값 max에 대해 비트 문자열로 표현하는 데 필요한 비트 수를 알고 싶습니다. 따라서 나중에 필요한만큼만 비트를 무작위로 샘플링 할 수 있으므로 스크립트의 효율성이 높아집니다.

보자 이후와 n비트, 우리는 2 값까지 표현할 수 N -1, 다음 수가 n임의의 값을 표현하는데 필요한 비트가 x천장 인 (로그 2 (X 1 +)). 따라서 밑의 2에 대한 로그의 상한을 계산하는 함수가 필요합니다.

log2() {
  local x=$1 n=1 l=0
  while (( x>n && n>0 ))
  do
    let n*=2 l++
  done
  echo $l
}

우리는 조건 n>0이 너무 커져서 너무 커지고 감싸지고 부정적이되면 루프가 종료되도록 보장됩니다.

2 단계 : 임의의 길이의 비트 열 샘플링 n

가장 휴대용 아이디어는 /dev/urandom(또는 /dev/random강력한 이유가 있더라도 ) 또는 bash의 내장 $RANDOM변수를 사용하는 것입니다. $RANDOM먼저 어떻게해야하는지 보자 .

옵션 A : 사용 $RANDOM

이것은 Eliah Kagan이 언급 한 아이디어를 사용합니다 . 기본적으로 $RANDOM15 비트 정수 $((RANDOM<<15|RANDOM))를 샘플링하기 때문에 30 비트 정수를 샘플링하는 데 사용할 수 있습니다 . 즉, 첫 번째 호출을 $RANDOM15 비트 왼쪽으로 이동하고 비트 단위 또는 두 번째 호출을 적용하여 $RANDOM두 개의 독립적으로 샘플링 된 비트 열을 효과적으로 연결합니다 (또는 적어도 bash의 내장 함수만큼 독립적 $RANDOM임).

45 비트 또는 60 비트 정수를 얻기 위해 이것을 반복 할 수 있습니다. bash는 더 이상 처리 할 수 ​​없지만 0과 2 60 -1 사이의 임의의 값을 쉽게 샘플링 할 수 있습니다 . 따라서 n 비트 정수를 샘플링하기 위해 길이가 15 비트 단위로 증가하는 임의의 비트 열이 n보다 크거나 같은 길이가 될 때까지 절차를 반복합니다. 마지막으로, 오른쪽으로 비트 단위로 적절히 시프트하여 너무 많은 비트를 잘라 내고, n 비트 랜덤 정수로 끝납니다.

get_n_rand_bits() {
  local n=$1 rnd=$RANDOM rnd_bitlen=15
  while (( rnd_bitlen < n ))
  do
    rnd=$(( rnd<<15|$RANDOM ))
    let rnd_bitlen+=15
  done
  echo $(( rnd>>(rnd_bitlen-n) ))
}

옵션 B : 사용 /dev/urandom

또한, 우리가 사용할 수 있습니다 od/dev/urandomn 비트의 정수를 맛볼 수 있습니다. od바이트 8, 즉 길이 8의 비트 열을 읽습니다. 이전 방법과 마찬가지로, 우리는 동일한 바이트 수만큼 샘플링 된 비트 수가 n보다 크거나 같고 너무 많은 비트를 잘라냅니다.

최소 n 비트를 얻는 데 필요한 최소 바이트 수는 n보다 크거나 같은 8의 최소 배수입니다 (즉, floor ((n + 7) / 8)).

이것은 최대 56 비트 정수로만 작동합니다. 1 바이트를 더 샘플링하면 64 비트 정수, 즉 bash가 처리 할 수없는 최대 2 64 -1 값을 얻을 수 있습니다.

get_n_rand_bits_alt() {
  local n=$1
  local nb_bytes=$(( (n+7)/8 ))
  local rnd=$(od --read-bytes=$nb_bytes --address-radix=n --format=uL /dev/urandom | tr --delete " ")
  echo $(( rnd>>(nb_bytes*8-n) ))
}

조각 정리하기 : 임의의 범위 에서 임의의 정수 가져 오기

우리는 샘플링 할 수 n해주기 비트 스트링을 비트,하지만 우리의 범위에서 샘플 정수로 원하는 0max, 균일 무작위로 , 어디에서 max, 임의적 일 수있는 두 가지의 반드시 전원을. (우리는 모듈로를 사용할 수 없기 때문에 바이어스를 만듭니다.)

우리가 값을 표현하는 데 필요한만큼의 비트를 샘플링하기 위해 열심히 노력한 이유는 max, n더 낮은 값을 샘플링 할 때까지 루프를 반복적으로 안전하게 사용하여 루프를 안전하게 샘플링 할 수 있다는 것입니다. 또는 같습니다 max. 최악의 경우 ( max2의 거듭 제곱) 각 반복은 50 %의 확률로 종료되고 최상의 경우 ( max2에서 1의 거듭 제곱 인) 첫 번째 반복은 확실하게 종료됩니다.

rand() {
  local rnd max=$1
  # get number of bits needed to represent $max
  local bitlen=$(log2 $((max+1)))
  while
    # could use get_n_rand_bits_alt instead if /dev/urandom is preferred over $RANDOM
    rnd=$(get_n_rand_bits $bitlen)
    (( rnd > max ))
  do :
  done
  echo $rnd
}

물건 정리

마지막으로, 우리는 사이 샘플 정수로 원하는 minmax, 어디에 minmax임의의 수 있습니다, 심지어 부정적인. 앞에서 언급했듯이 이것은 이제 사소한 것입니다.

bash 스크립트에 모두 넣겠습니다. 일부 인수 구문 분석 물건을 할 ... 우리는 두 개의 인수하고자 min하고 max, 또는 하나 개의 인수 max, min기본값을 0.

# check number of parameters
if (( $# != 1 && $# != 2 ))
then
  cat <<EOF 1>&2
Usage: $(basename $0) [min] max

Returns an integer distributed uniformly at random in the range {min..max}
min defaults to 0
(max - min) can be up to 2**60-1  
EOF
  exit 1
fi

# If we have one parameter, set min to 0 and max to $1
# If we have two parameters, set min to $1 and max to $2
max=0
while (( $# > 0 ))
do
  min=$max
  max=$1
  shift
done

# ensure that min <= max
if (( min > max ))
then
  echo "$(basename $0): error: min is greater than max" 1>&2
  exit 1
fi

... 그리고, 마지막으로, 사이의 임의의 값 균일하게 샘플 minmax우리 사이의 임의의 정수 샘플 0과의 절대 값 max-min, 및 추가 min의 최종 결과. :-)

diff=$((max-min)) && diff=${diff#-}

echo $(( $(rand $diff) + min ))

영감을받은 , 내가 사용하려고 할 수 dieharder 테스트 및 벤치마킹이 PRNG로, 여기에 내 결과를했습니다. :-)


귀하의 솔루션은 다음 sizeof(int) == 8으로 인해 (64 비트) 가정합니다.--format=u
jfs

1
귀하의 솔루션은 random.py가 어떻게 작성되는지 알려줍니다. random.Random클래스는 53 비트를 사용합니까? 임의의 큰 난수 (다중 호출)를 반환하는 생성기는를 random.SystemRandom사용하여 os.urandom()구현 할 수있는 것과 동일한 작업을 수행 /dev/urandom합니다.
jfs

uL은 범위에 대해 sizeof (long)> = 8을 의미합니다. 보장되지 않습니다. u8을 사용하여 플랫폼에 그러한 정수가 있다고 주장 할 수 있습니다.
jfs

@ JFSebastian 나는 지금까지 내 스크립트가 long int의 크기에 대한 가정을 하드 코딩하지 않는다고 생각했다. 잠재적으로 long signed int의 크기가 64 비트보다 크거나 작은 경우에도 작동합니다 (예 : 128 비트). 그러나 내가 사용 --format=u8하면 가정을 하드 코딩합니다 sizeof(int)==8. 반면에, 사용하는 경우 --format=uL나 플랫폼 있다고 생각하지 않습니다 : 아무 문제가 없다 64 비트 정수는 여전히 낮은 무언가로 긴의 int를 정의합니다. 따라서 기본적으로 --format=uL더 많은 유연성을 허용 한다고 주장 합니다. 당신의 생각은 무엇입니까?
Malte Skoruppa

거기 long long가 될 수 있습니다 64 비트는 일부 플랫폼에서 32 비트는 = 동안 INT = 긴. 모든 플랫폼에서 범위를 보장 할 수없는 경우 0..2 ** 60 범위를 청구해서는 안됩니다. 다른 한편으로 bash는 그러한 플랫폼 에서이 범위 자체를 지원하지 않을 수도 있습니다 (모름은 maxint_t를 사용하고 고정 범위를 주장하려는 경우 u8이 더 정확합니다 ( od범위가 다음과 같은 경우 maxint 지정을 지원하지 않습니다) bash의 플랫폼에 따라 다를 수있는 범위는 무엇입니까? bash가 모든 OS에서 지원하는 전체 범위 또는 고정 범위를 원하십니까?
jfs

6

zsh가 될 수 있습니까?

max=1000
integer rnd=$(( $(( rand48() )) * $max ))

와 함께 씨앗을 사용할 수도 있습니다 rand48(seed). 참조 man zshmodulesman 3 erand48관심이있는 경우에 대한 자세한 설명.


나는 개인적으로 zsh를 사용하지 않지만 이것은 위대한 추가 사항입니다 :)
Malte Skoruppa

5
$ python -c 'import random as R; print(R.randint(-3, 5**1234))'

python Redhat, 데비안 기반 시스템에서 사용할 수 있습니다.


+1 Ah, 펄 솔루션 과 함께 파이썬 솔루션이 필요했습니다. 감사합니다 :)
Malte Skoruppa

5

당신의 숫자하려는 경우 0 을 통해 (2 ^ N)를 -1 여기서 n은 모드 8 = 0 당신은 단순히 얻을 수있는 N / 8 바이트를 /dev/random. 예를 들어, 임의의 10 진수 표현을 얻으려면 다음을 수행하십시오 int.

od --read-bytes=4 --address-radix=n --format=u4 /dev/random | awk '{print $1}'

n 비트 만 가져 가려면 먼저 ceiling (n / 8) 바이트를 가져 와서 원하는 양으로 오른쪽 이동 하십시오. 예를 들어 15 비트를 원하는 경우 :

echo $(($(od --read-bytes=2 --address-radix=n --format=u4 /dev/random | awk '{print $1}') >> 1))

당신은 당신이 절대적으로 확실한 경우 임의성의 품질에 대해 걱정하지 않는다 당신은 보장 할 최소한의 실행시 사용할 수있는 /dev/urandom대신을 /dev/random. 사용하기 전에 무엇을하고 있는지 확인하십시오 /dev/urandom!


고맙습니다. 따라서을 사용하여 n임의의 바이트를 가져 와서 /dev/urandom형식화하십시오 od. 이 답변 과 정신 비슷합니다 . 둘 다 똑같이 좋습니다 :) 둘 다 0에서 2 ^ (n * 8) -1 비트의 고정 범위를 갖는 단점이 있지만, 여기서 n은 바이트 수입니다. 나는 2 ^ 32-1 까지임의의 범위에 대한 방법을 선호 하지만 더 낮은 것을 선호합니다 . 이것은 편견 어려움을 만듭니다.
Malte Skoruppa

/dev/urandom대신 사용하도록 편집 /dev/random-사용할 이유가 없으며 /dev/random실제로 비용이 많이 들거나 느리거나 시스템의 다른 부분이 느려질 수 있습니다. (무료로 편집
해보고

: 그것은 정확히 반대해야 하지 않는 한 사용은 / dev / urandom을 당신이 알고있는 당신은 / dev / 랜덤 필요 . 대부분의 경우 urandom을 사용할 수없는 /dev/urandom것보다 결과가 훨씬 나쁘다고 가정하는 것은 올바르지 않습니다 . 일단 초기화 되면 (시스템 시작시); 그 결과는 Linux의 거의 모든 응용 프로그램 만큼 좋습니다 . 어떤 시스템에서는 무작위와 소변이 동일합니다. /dev/random/dev/urandom/dev/random
jfs

1
--format=u이론 보다 적을 수 --format=u4있기 때문에 로 대체해야합니다 . sizeof(int)4
jfs

@JFSebastian 이 논문 은이 주제에 관해 매우 흥미로운 토론을합니다. 그들의 결론은 둘 것 같다 /dev/random/dev/urandom만족스럽지, 그것은 "리눅스는 그 때까지 블록이 적절한 종자 엔트로피를 수집하고 그 이후처럼 행동했다고 보안 RNG를 추가해야합니다 urandom."
l0b0 2018 년

3

외부 도구 사용을 반대한다고 가정하면 요구 사항을 충족해야합니다.

rand=$(perl -e 'print int(rand(2**32-1))'); 

그것은 rand상한을 매개 변수로 사용하는 perl의 기능을 사용 하고 있습니다. 원하는대로 설정할 수 있습니다. 추상 수학적 정의에서 이것이 무작위성에 얼마나 근접한지는이 사이트의 범위를 벗어나지 만 매우 민감한 암호화 등을 위해 필요하지 않는 한 괜찮습니다. 어쩌면 거기에도 의견이 없습니다.


많은 수의이 휴식 예를 들면, ** 1234 5
JFS

1
@JFSebastian 네 그렇습니다. OP가 지정된 이후에 이것을 게시 1^32-1했지만 더 큰 숫자를 조정해야합니다.
terdon

2

가장 가까운 (2 ^ X) -1을 원하는 최대 값보다 크거나 같아야하며 비트 수를 가져와야합니다. 그런 다음 / dev / random을 여러 번 호출하고 충분한 비트가 될 때까지 모든 비트를 함께 추가하여 너무 많은 비트를 자릅니다. 결과 숫자가 최대 반복보다 큰 경우. 최악의 경우 최대 값보다 낮은 임의의 숫자를 얻을 확률이 50 %보다 높으므로 (이 최악의 경우) 평균 두 번의 통화를받습니다.


이것은 효율성을 향상시키기 위해 실제로 좋은 아이디어입니다. Ramesh의 대답l0b0의 대답 은 기본적으로에서 임의의 비트를 얻지 /dev/urandom만 두 가지 대답 모두 항상 8 비트의 배수입니다. 10 진수로 포맷하기 전에 낮은 범위에 비해 너무 많은 비트를 잘라내는 od것은 루프가 예상 한대로 2 회 반복 만 예상하므로 효율성을 향상시키는 것이 좋습니다. 이것은 언급 된 답변 중 하나와 결합되어 아마도 갈 길입니다.
Malte Skoruppa

0

당신의 대답은 흥미롭지 만 꽤 깁니다.

임의로 큰 숫자를 원하면 도우미에서 여러 개의 임의의 숫자를 결합 할 수 있습니다.

# $1 - number of 'digits' of size base
function random_helper()
{
  base=32768
  random=0
  for((i=0; i<$1; ++i)); do
    let "random+=$RANDOM*($base**$i)"
  done
  echo $random
}

문제가 편견이라면 제거하십시오.

# $1 - min value wanted
# $2 - max value wanted
function random()
{
  MAX=32767
  min=$1
  max=$(($2+1))
  size=$((max-min))
  bias_range=$((MAX/size))
  while
    random=$RANDOM
  [ $((random/size)) -eq $bias_range ]; do :; done
  echo $((random%size+min))
}

이 기능들을 결합

# $1 - min value wanted
# $2 - max value wanted
# $3 - number of 'digits' of size base
function random()
{
  base=32768
  MAX=$((base**$3-1))
  min=$1
  max=$(($2+1))
  size=$((max-min))
  bias_range=$((MAX/size))
  while
    random=$(random_helper)
  [ $((random/size)) -eq $bias_range ]; do :; done
  echo $((random%size+min))
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.