랜드()를 사용할 때 이 특정 색상 패턴을 얻는 이유는?
나는 다음과 같은 이미지 파일을 만들려고 했다.
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; */
}
나는 처음에 다른 모든 사람들이 가지고 있는 것과 같은 대답을 할 예정이었고 이것을 의 쟁점으로 돌리려고 했다.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()
이건 네가 예상할 수 있는 거야, 그냥 소음일 뿐이야.이것을 "Image C"라고 불러라.
(x + y) % rand()
여기 픽셀 좌표를 함께 추가하고 나머지 부분을 무작위 숫자로 나눈다.영상이 1024x1024인 경우 합계는 [0-2046] 범위에 있다.당신이 다이빙하고 있는 임의의 숫자는 [0,RAND_MAX] 범위에 있으며, 여기서 RAND_MAX는 최소 32k이고 일부 시스템에서는 20억이다.다른 말로 하자면, 기껏해야 16분의 1의 확률로 나머지가 그저 그런 것이 아닐 가능성이 있다.(x + y)
따라서 대부분의 경우 이 기능은 +x +y 방향으로 파란색 증가의 구배를 생성할 것이다.
하지만 당신은 가장 낮은 8비트만을 사용하고 있다. 왜냐하면 당신은 a를 반환하기 때문이다.uint8_t
256픽셀의 그라데이션 줄무늬가 있을 겁니다.
이것을 "이미지 A"라고 불러라.
(x - y) % rand()
여기서 당신은 비슷한 것을 하지만 뺄셈으로 한다.x가 y보다 크기만 하면 이전 이미지와 비슷한 것을 갖게 될 것이다.그러나 y가 더 큰 경우에는 그 결과가 매우 큰 수가 되기 때문이다.x
그리고y
서명되지 않은(부정 결과가 서명되지 않은 유형의 범위 상단으로 감싼 경우) 다음% rand()
발차기를 하면 실제로 소리가 난다.
이것을 "Image 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)%2
0과 1을 똑같이 자주 생산하지 않는다.홀수를 짝수로 곱하면 짝수가 된다.짝수를 짝수로 곱한 것도 짝수다.홀수를 곱한 홀수만 홀수여서 홀수인 것이다.%2
시간의 4분의 3이라도 되는 값에서 0의 3분의 1을 산출할 것이다.
여기 어디에 있는지 클로즈업 해봅시다.((x * y % 1024) % rand()) % 2
이미지 B가 선택될 수 있도록 진실이다.두 좌표가 홀수인 곳을 정확히 고르고 있는 겁니다.
다음은 이미지 C를 선택할 수 있는 위치의 클로즈업:
마지막으로 이미지 B가 선택된 조건을 조합하십시오.
이미지 C가 선택된 경우:
결과 조합은 다음과 같이 판독할 수 있다.
50% 확률로 이미지 A의 픽셀을 사용한다.나머지 시간은 이미지 B와 이미지 C, 두 좌표가 홀수인 경우 B, 둘 중 하나가 짝수인 경우 C 사이에서 선택한다.
마지막으로, 세 가지 색상에 대해 같은 작업을 하지만 방향이 다르기 때문에 패턴은 각 색상에서 서로 다른 방향으로 방향이 지정되고 여러분이 보고 있는 교차 스트립이나 격자 무늬를 생성한다.
당신이 코드에서 하고 있는 많은 계산들이 정말로 무작위적인 값으로 이어지지 않을 것이다.여기 보이는 선은 x와 y의 상대적 값이 서로 교환되는 장소와 일치하며, 그 때 당신은 근본적으로 다른 공식을 사용한다.예를 들어, 컴퓨터(x + y) % rand()
일반적으로 그 가치를 되돌려 줄 것이다.x + y
, 그 이후rand()
보다 훨씬 더 큰 숫자를 반환할 것이다.x + y
…을 감안하여RAND_MAX
보통 꽤 많은 숫자다.그런 의미에서 백색소음을 되돌릴 수 있으리라고 기대해서는 안 된다. 왜냐하면 당신이 사물을 생성하기 위해 사용하는 알고리즘은 백색소음을 발생시키는 것에서 편향되어 있기 때문이다.화이트 노이즈를 사용하려면 각 픽셀을 다음으로 설정하십시오.rand()
여기 위에 있는 것과 같은 멋진 패턴을 원하지만, 여기 저기에 있는 약간의 무작위성을 가지고 싶다면, 당신이 작성한 코드를 계속 사용하라.
덧붙여 @pm100은 논평에서 지적한 바와 같이, 다음과 같다.rand
함수는 진정으로 임의의 숫자를 반환하지 않고 대신 유사 함수를 사용하여 값을 산출한다.의 rand
많은 시스템에서, 짧은 버스트에서 무작위로 보일 수 있지만 실제로는 확실히 무작위로 보일 수 없는 숫자를 생성하는 선형 결합 발전기라고 불리는 가성수 생성기의 유형을 사용한다.예를 들어, 여기 위키피디아의 애니메이션이 선형 결합 발전기로 선택한 공간의 무작위 포인트가 어떻게 고정된 수의 하이퍼플레인으로 떨어지는지를 보여준다.
x, y, z 좌표를 R, G, B 좌표로 바꾸면 이는 프로그램에서 생성되는 출력과 현저히 유사해 보인다.위에 언급된 다른 측면은 아마도 훨씬 더 뚜렷해질 것이기 때문에, 나는 이것이 아마도 여기서 핵심 문제는 아닐 것이라고 추측한다.
고품질 난수를 찾는다면 고품질 난수원을 사용해야 할 것이다.C에서는 다음에서 바이트를 읽을 수 있다./dev/urandom/
(Linux와 유사한 시스템에서) 상당히 균일하게 랜덤 값을 제공하는.C++는 현재 표준 라이브러리에 수많은 우수한 무작위 수 생성 원시 요소들을 가지고 있다.
'programing' 카테고리의 다른 글
V-툴팁:메서드에서 팝업 닫기 (0) | 2022.04.20 |
---|---|
Java에서 "실행 가능" 대 "스레드 확장" (0) | 2022.04.20 |
람다를 연재하는 방법? (0) | 2022.04.20 |
sprintf/snprintf 중 어느 것이 더 안전한가? (0) | 2022.04.20 |
루트 Vue 구성 요소의 Vue.use vs Vue.component (0) | 2022.04.20 |