programing

난수 생성을 시드하는 데 시간을 사용하는 대안이 있습니까?

bestprogram 2023. 10. 9. 23:27

난수 생성을 시드하는 데 시간을 사용하는 대안이 있습니까?

여러 개의 코드 인스턴스(2000개 정도의 인스턴스)를 컴퓨팅 클러스터에서 동시에 실행하려고 합니다.작업을 제출하면 클러스터에서 노드가 자주 열리므로 노드당 여러 개의 작업이 수행됩니다.이 값은 타임 시드를 사용하는 랜덤 숫자 생성에서 많은 인스턴스에 대해 동일한 값을 생성하는 것으로 보입니다.

대신 사용할 수 있는 간단한 대안이 있습니까?재현성과 보안은 중요하지 않고, 독특한 씨앗을 빠르게 생성하는 것이 중요합니다.이를 위한 가장 간단한 접근법은 무엇이며, 가능하다면 크로스 플랫폼 접근법이 좋을 것입니다.

rdtsc명령어는 상당히 신뢰할 수 있는 (그리고 무작위적인) 씨앗입니다.

에서는를 수 .__rdtsc()

GNUC에서는 다음을 통해 액세스할 수 있습니다.

unsigned long long rdtsc(){
    unsigned int lo,hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((unsigned long long)hi << 32) | lo;
}

명령어는 프로세서의 전원이 켜진 이후 총 의사 주기를 측정합니다.오늘날의 기계의 높은 주파수를 고려할 때, 두 개의 프로세서가 동시에 부팅되고 동일한 속도로 클록킹되더라도 동일한 값을 반환할 가능성은 매우 낮습니다.

다른 프로세스를 시작하는 과정이 있을 것 같습니다.사용할 씨앗을 통과시키세요.그러면 해당 마스터 프로세스를 각 프로세스별로 랜덤하게 전달하여 시드로 사용할 수 있습니다.그렇게 하면 정말로 선택된 임의의 씨앗은 단 한 개뿐이고...시간을 내시면 됩니다.

다른 프로세스를 실행하는 마스터 프로세스가 없는 경우 각 프로세스에 적어도 고유한 인덱스가 있다면 한 프로세스에서 메모리(공유 메모리인 경우) 또는 파일(공유 디스크인 경우)에 일련의 난수를 생성한 다음 각 프로세스에서 인덱스의 난수를 꺼내 시드로 사용하도록 하는 것입니다.

하나의 씨앗에서 나온 일련의 난수만큼 더 고른 씨앗의 분포를 제공하는 것은 없을 것입니다.

PID와 시간의 조합은 고유 시드를 얻기에 충분해야 합니다.100% 크로스 플랫폼은 아니지만 *nix 플랫폼과 Windows에서 99.9%의 이점을 얻을 수 있습니다.이와 같은 것이 효과가 있을 것입니다.

srand((time(NULL) & 0xFFFF) | (getpid() << 16));

./dev/urandom*nix 시스템에는 있지만 Windows에는 이와 동등한 기능이 없습니다.

unsigned seed;

read(open("/dev/urandom", O_RDONLY), &seed, sizeof seed);
srand(seed); // IRL, check for errors, close the fd, etc...

저는 또한 더 나은 난수 생성기를 추천합니다.

C++11을 사용할 수 있다면 다음을 고려해 보십시오.std::random_device. 종합적인 가이드를 위해 링크를 보는 것을 추천합니다.

비디오 링크에서 필수 메시지 추출 : 절대 사용해서는 안 됩니다.srand&rand 합니다를 합니다.std::random_device그리고.std::mt19937 당신이 . --합니다.

#include <iostream>
#include <random>
int main() {
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_int_distribution<int> dist(0,99);
    for (int i = 0; i < 16; i++) {
        std::cout << dist(mt) << " ";
    }
    std::cout << std::endl;
}

Cstd lib time() 함수에서 초 단위로 측정되는 직선 시간 대신 프로세서의 카운터를 사용할 수 있습니까?대부분의 프로세서에는 무료 실행 틱 수가 있으며, 예를 들어 x86/x64에는 타임 스탬프 카운터가 있습니다.

타임 스탬프 카운터는 펜티엄 이후 모든 x86 프로세서에 존재하는 64비트 레지스터입니다.재설정 이후 틱 수를 카운트합니다.

(이 페이지에는 여러 플랫폼에서 이 카운터에 액세스할 수 있는 여러 가지 방법이 있습니다. -- gcc/ms visual c/etc)

타임스탬프 카운터에 결함이 없는 것은 아니며, 프로세서 간에 동기화되지 않을 수도 있습니다(아마 응용 프로그램에 관심이 없을 것입니다).또한 절전 기능을 통해 프로세서가 작동하거나 작동하지 않을 수도 있습니다(다시 한 번 신경 쓰지 않을 수도 있음).

그냥 한가지 생각...GUID(16바이트)를 생성하고 4바이트 또는 8바이트 청크(시드의 예상 너비에 따라 다름)를 합하여 정수 랩어라운드를 허용합니다.결과를 시드로 사용합니다.

일반적으로 GUID는 MAC 주소와 같은 컴퓨터를 생성한 컴퓨터의 특성을 캡슐화합니다. 이는 두 개의 다른 컴퓨터가 동일한 랜덤 시퀀스를 생성하게 되는 것을 다소 불가능하게 됩니다.

한 API/라이브러리를 은 그리 한 API/(:UuidCreate Win32에서.uuid_generate(리눅스).

창문들

을 합니다.CryptGenRandom()그리고.RtlGenRandom()은 당신에게 할 수 할 것입니다 그들은 당신이 시드로 사용할 수 있는 랜덤 바이트 배열을 제공할 것입니다.

msdn 페이지에서 문서를 찾을 수 있습니다.

리눅스/유닉스

의 오픈슬의 를를 할 수 있습니다.RAND_bytes()리눅스에서 임의 수의 바이트를 얻을 수 있습니다.가를 입니다./dev/random

이를 종합하면 다음과 같습니다.

#ifdef _WIN32
  #include <NTSecAPI.h>
#else
  #include <openssl/rand.h> 
#endif

uint32_t get_seed(void)
{
  uint32_t seed = 0;

#ifdef _WIN32
  RtlGenRandom(&seed, sizeof(uint32_t) );
#else
  RAND_bytes(&seed, sizeof(uint32_t) ); 
#endif

  return seed;
}

openssl은 기본적으로 Cryptographic으로 안전한 PRNG를 제공하므로 직접 사용할 수 있습니다.자세한 내용은 이쪽.

당신이 합리적인 POSIX-ish 시스템을 사용한다고 가정할 때, 당신은 다음과 같이clock_gettime. 이는 현재 시간을 나노초 단위로 제공하며, 이는 모든 실제적인 목적에서 동일한 값을 두 번 얻는 것이 불가능하다는 것을 의미합니다.(이론적으로 좋지 않은 구현은 훨씬 더 낮은 해상도를 가질 수 있습니다. 예를 들어 밀리초에 100만을 곱하는 것으로 볼 수 있지만, Linux와 같이 반쯤 괜찮은 시스템에서도 실제 나노초의 결과를 얻을 수 있습니다.)

고유성이 중요한 경우, 다른 사람이 어떤 ID를 주장했는지 알 수 있도록 각 노드별로 정렬해야 합니다.이 작업은 "누구든지 ID x를 주장했습니까?"라는 프로토콜을 사용하여 수행하거나 각 노드가 다른 노드에 할당되지 않은 ID를 선택할 수 있도록 미리 배치할 수 있습니다.

(GUID는 기기의 MAC를 사용하므로 "미리 준비" 범주에 속합니다.)

어떤 형태로든 합의가 없으면 두 노드가 같은 ID를 클릭할 위험이 있습니다.

언급URL : https://stackoverflow.com/questions/7617587/is-there-an-alternative-to-using-time-to-seed-a-random-number-generation