rand ()를 사용할 때 왜이 특정 색상 패턴을 얻습니까?


170

다음과 같이 이미지 파일을 만들려고했습니다.

uint8_t raw_r[pixel_width][pixel_height];
uint8_t raw_g[pixel_width][pixel_height];
uint8_t raw_b[pixel_width][pixel_height];
uint8_t blue(uint32_t x, uint32_t y)
{
    return (rand()%2)? (x+y)%rand() : ((x*y%1024)%rand())%2 ? (x-y)%rand() : rand();
}
uint8_t green(uint32_t x, uint32_t y)
{
    return (rand()%2)? (x-y)%rand() : ((x*y%1024)%rand())%2 ? (x+y)%rand() : rand();
}
uint8_t red(uint32_t x, uint32_t y)
{
    return (rand()%2)? (y-x)%rand() : ((x*y%1024)%rand())%2 ? (x+y)%rand() : rand();
}

for (y=0; y<pixel_height; ++y)
{
    for (x=0; x<pixel_width; ++x)
    {
        raw_b[x][y]=blue(x, y);
        raw_g[x][y]=green(x, y);
        raw_r[x][y]=red(x, y);
    }
}

나는 임의의 것을 얻을 것으로 예상했다 (흰색 소음). 그러나 결과는 흥미 롭습니다.

이유를 알고 있습니까?


편집하다

이제는와 관련이 없음이 분명합니다 rand().

이 코드를 사용해보십시오 :

for (x=0; x<pixel_width; ++x)
    for (y=0; y<pixel_height; ++y)
    {
        r[x][y] = (x+y);
        g[x][y] = (y-x);
        /* b[x][y] = rand()%2? x : y; */
    }


26
cos rand isnt rand-멋진 데모입니다. 100 % 결정적입니다
pm100


50
@ PM100 : bames53의 답변이 잘 설명했듯이 완벽한 난수 생성기를 사용하더라도 동일한 패턴을 얻을 수 있습니다.
TonyK

13
실례합니다 : x와 y 좌표를 사용하여 픽셀 값을 계산하고 있는데 왜 그 값이 좌표와 독립적 일 것으로 기대하십니까? 이미지가 균일하게 무작위로 보인다면 이것이 필요한 것입니다. 맞습니까?
Thomas Padron-McCarthy

15
교훈 : 임의의 숫자로 임의의 것을하는 것은 임의의 결과를 생성하지 않습니다 :)
Hagen von Eitzen

답변:


355

나는 처음에 다른 모든 사람들과 같은 대답을하려고했고이 문제에 대한 답을 얻었습니다 rand(). 그러나 나는 그렇게하는 것이 더 낫다고 생각하고 대신 수학이 실제로 생성하는 분포를 분석했습니다.

TL; DR : 보이는 패턴은 기본 난수 생성기와 아무 관련이 없으며 단순히 프로그램이 숫자를 조작하는 방식 때문입니다.

나는 모두 비슷하기 때문에 파란색 기능을 고수 할 것입니다.

uint8_t blue(uint32_t x, uint32_t y) {
    return (rand() % 2)                  ? (x + y) % rand() :
           ((x * y % 1024) % rand()) % 2 ? (x - y) % rand() :
                                           rand();
}

각각의 픽셀 값은 세 가지 기능들 중 하나로부터 선택된다 : (x + y) % rand(), (x - y) % rand()rand();

이들 각각에 의해 생성 된 이미지를 보자.

  • rand()

이것이 바로 잡음입니다. 이것을 "이미지 C"라고 부릅니다.

여기에 이미지 설명을 입력하십시오


  • (x + y) % rand()

여기에서는 픽셀 좌표를 더하고 나머지를 난수로 나누지 않습니다. 이미지가 1024x1024 인 경우 합계는 [0-2046] 범위에 있습니다. 다이빙하는 난수는 [0, RAND_MAX] 범위에 있으며 RAND_MAX는 32k 이상이고 일부 시스템에서는 20 억입니다. 다른 말로하면, 나머지 16 분의 1만이 16에서 1의 확률로 존재합니다 (x + y). 따라서이 함수는 대부분 + x + y 방향으로 파란색이 증가하는 그래디언트를 생성합니다.

그러나을 반환하기 때문에 가장 낮은 8 비트 만 사용 uint8_t하므로 너비가 256 픽셀 인 그라디언트 줄무늬가 나타납니다.

이것을 "이미지 A"라고 부릅니다.

여기에 이미지 설명을 입력하십시오


  • (x - y) % rand()

여기에 비슷한 것이 있지만 빼기가 있습니다. x가 y보다 크면 이전 이미지와 비슷한 것이 있습니다. Y가 큰 경우 그러나, 결과는 때문에 매우 큰 숫자 xy부호가 (부정적인 결과는 부호없는 형식의 범위의 상단에 랩 어라운드는) 다음 % rand()에서 차기 당신은 실제로 소음 얻을.

이것을 "이미지 B"라고 부릅니다.

여기에 이미지 설명을 입력하십시오

최종 이미지의 각 픽셀은 기능 rand() % 2및을 사용하여이 세 이미지 중 하나에서 가져옵니다 ((x * y % 1024) % rand()) % 2. 이 중 첫 번째는 50 % 확률로 선택하여 읽을 수 있습니다 ( rand()낮은 비트와 관련된 문제는 무시 함 ).

여기 어디의 근접 촬영입니다 rand() % 2 은 이미지 A가 선택 이 참 (흰색 픽셀) 인 .

여기에 이미지 설명을 입력하십시오

두 번째 기능은 ((x * y % 1024) % rand()) % 2다시 문제가 있습니다.rand() 나누고있는 것보다 (x * y % 1024)최대 1023 인 문제를 가지고 있습니다. 그런 다음 (x*y%1024)%20과 1을 똑같이 자주 생성하지 않습니다. 홀수에 짝수를 곱한 값은 짝수입니다. 짝수를 곱한 짝수도 짝수입니다. 홀수에 홀수를 곱한 %2값만 홀수이므로 시간의 3/4조차도 0의 3/4 시간을 생성합니다.

다음 ((x * y % 1024) % rand()) % 2은 이미지 B를 선택할 수있는 위치의 근접 촬영입니다 . 두 좌표가 홀수 인 곳을 정확하게 선택합니다.

여기에 이미지 설명을 입력하십시오

이미지 C를 선택할 수있는 곳은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

마지막으로 이미지 B가 선택된 조건을 결합하십시오.

여기에 이미지 설명을 입력하십시오

이미지 C가 선택된 위치 :

여기에 이미지 설명을 입력하십시오

결과 조합은 다음과 같이 읽을 수 있습니다.

확률이 50 %이면 이미지 A의 픽셀을 사용합니다. 나머지 시간은 이미지 B와 이미지 C, 두 좌표가 홀수 인 B, 둘 중 하나가 짝수 인 C 사이에서 선택됩니다.

마지막으로 세 가지 색상에 대해 동일한 작업을 수행하지만 방향이 다르면 각 색상에서 패턴의 방향이 다르며보고있는 교차 스트립 또는 격자 패턴이 생성됩니다.


45

코드에서 수행하는 많은 계산은 실제로 임의의 값으로 이어지지 않습니다. 당신이보고있는 날카로운 선은 x와 y 좌표의 상대 값이 서로 거래되는 장소에 해당하며, 그럴 때 근본적으로 다른 공식을 사용하고 있습니다. 예를 들어, 컴퓨팅 (x + y) % rand()은 일반적으로 값을 돌려줍니다 x + y. 왜냐하면 rand()의지가 (보통)보다 훨씬 큰 숫자를 반환하기 때문 입니다. 위에서 본 것과 같은 멋진 패턴을 원하지만 여기저기서 약간의 무작위성을 던지면 작성한 코드를 계속 사용하십시오.x + yRAND_MAX 일반적으로 상당히 큰 숫자 때문 입니다. 그런 의미에서, 물건을 생성하는 데 사용하는 알고리즘이 백색 잡음을 생성하는 데 편향되어 있지 않기 때문에 백색 잡음을 되 찾을 것으로 기 대해서는 안됩니다. 화이트 노이즈를 원하면 각 픽셀을rand()

또한 @ pm100이 주석에서 언급했듯이 rand함수는 실제로 임의의 숫자를 반환하지 않으며 대신 의사 난수 함수를 사용하여 값을 생성합니다. rand많은 시스템에서 기본 구현은 짧은 연속 버스트가 무작위로 나타날 수 있지만 실제로는 비 랜덤 인 숫자를 생성 하는 선형 합동 생성기 라고하는 의사 난수 생성기 유형을 사용합니다 . 예를 들어, 다음은 선형 합동 발생기로 선택한 공간의 임의의 점이 고정 된 수의 초평면으로 떨어지는 방법을 보여주는 Wikipedia의 애니메이션입니다.

이미지

x, y 및 z 좌표를 R, G 및 B 좌표 로 바꾸면 프로그램에서 생성되는 출력과 매우 유사합니다. 위에서 언급 한 다른 측면이 훨씬 더 두드러지기 때문에 이것이 아마도 핵심 문제가 아닌 것 같습니다.

고품질 난수를 찾으려면 고품질 난수를 사용해야합니다. C에서는 /dev/urandom/리눅스와 같은 시스템 에서 바이트를 읽는 것을 고려할 수 있는데, 이는 상당히 균일 한 임의의 값을 제공합니다. C ++은 표준 라이브러리에 여러 가지 난수 생성 프리미티브가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.