한쪽 끝으로 편향된 연속 가중치 가중 분포


28

저는 현재 게임을위한 파티클 시스템에 공헌하고 있으며 이미 터 모양을 개발하고 있습니다.

선 또는 직사각형 영역을 따라 균일 한 무작위 분포가 문제없이 작동합니다.

그러나 이제 저는이 분포에서 1 차원 그라디언트와 같은 것을 원합니다. 예를 들어 값이 낮을수록 값이 높을수록 더 일반적입니다.

이 문제에 적합한 수학 용어가 무엇인지 알지 못하므로 검색 기술이 다소 쓸모가 없습니다. 파티클 시스템이 효율적이어야하므로 계산적으로 간단한 것이 필요합니다.



아무도 미적분학에 대해 언급하지 않습니까?
Alec Teal

답변:


42

이 사진을보십시오 :

커브 매핑

(랜덤) 값을 곡선에 매핑하는 과정을 보여줍니다. 균일하게 분포 된 랜덤 값 X를 0에서 1까지의 범위로 생성한다고 가정합니다.이 값을 곡선에 매핑하여, 즉 X 대신 f (X)를 사용하여 원하는 방식으로 분포를 왜곡 할 수 있습니다 .

이 그림에서 첫 번째 곡선은 더 높은 값을 만들 가능성이 높습니다. 두 번째는 낮은 값일 가능성이 높습니다. 세 번째는 가치를 중간에 모으는 것입니다. 곡선의 정확한 공식은 실제로 중요하지 않으며 원하는대로 선택할 수 있습니다.

예를 들어 첫 번째 커브는 제곱근과 비슷하고 두 번째 커브는 정사각형입니다. 세 번째는 큐브와 비슷하며 번역 된 것입니다. 제곱근이 너무 느리다고 생각하면 첫 번째 곡선은 f (X) = 1- (1-X) ^ 2처럼 보입니다. 또는 과장법 : f (X) = 2X / (1 + X).

네 번째 곡선에서 알 수 있듯이 미리 계산 된 룩업 테이블을 사용할 수 있습니다. 못생긴 곡선으로 보이지만, 아마도 입자 시스템에 충분할 것입니다.

이 일반적인 기술은 매우 간단하고 강력합니다. 필요한 분포가 무엇이든 곡선 매핑을 상상하면 곧 수식을 고안 할 수 있습니다. 또는 엔진에 편집기가있는 경우 곡선의 시각적 편집기를 만드십시오!


철저하고 이해하기 쉬운 설명에 감사드립니다. 다른 모든 게시물도 매우 도움이되었지만 가장 쉽고 빠른 게시물을 이해할 수있었습니다. 그것은 bc를 내밀어 내 물건을 이해하는 방법에 대한 자리를 실제로 맞았습니다. 그리고 당신이 설명하는 측면은 내가 찾은 것 (또는 방황하는 것)입니다! 나중에 많은 경우에 이것을 사용할 수 있습니다. 다시 thx !!! btw, 나는 그들의 곡선 중 일부를 가지고 놀았으며 그것은 매력처럼 작동합니다.
didito

5
참고 :이를 Quantile 함수라고합니다. en.wikipedia.org/wiki/Quantile_function
Neil G

8

더 긴 설명 :

@didito가 요청한 기울기와 같은 원하는 확률 분포 가있는 경우 함수라고 설명 할 수 있습니다. 0에서 확률이 0.0 인 삼각 분포를 원하고 0에서 1 사이의 난수를 선택한다고 가정 해 봅시다. y = x로 쓸 수 있습니다.

다음 단계는이 함수의 적분을 계산하는 것입니다. 이 경우 입니다. 0에서 1까지 평가되었으므로 1/2입니다. 이것은 의미가 있습니다. 밑변이 1이고 높이가 1 인 삼각형이므로 면적이 ½입니다.x=1x2

그런 다음 0에서 영역까지 임의의 점을 균일하게 선택합니다 (이 예에서는 1/2). 이것을 z라고합시다. (우리는 누적 분포 에서 균일하게 선택 합니다.)

다음 단계는 뒤로 이동하여 x의 값 (x̂이라고 함)이 z의 영역에 해당하는 것을 찾는 것입니다. 0에서 x̂까지 평가 된 z와 동일한 찾고 있습니다. 당신이 해결되면 하면 얻을 .x=1x21x̂2=zx̂=2z

이 예에서는 z를 0에서 ½로 선택한 다음 원하는 임의의 숫자는 입니다. 간단히 말해 eBusiness에서 권장 하는대로 로 작성할 수 있습니다 .2zrand(0,1)


가치있는 입력을위한 thx. 저는 항상 숙련 된 사람들이 어떻게 문제를 해결하는지 듣고 싶습니다. 그러나 나는 여전히 정직하기 위해 내 머리를 감쌀 필요가있다.
didito

대단해. 나는 항상 sqrt(random())내 평생을 보냈지 만 경험적으로왔다. 난수를 곡선에 묶으려고했는데 효과가있었습니다. 이제 좀 더 수학에 능숙 해 졌는데 왜 작동하는지 아는 것이 매우 중요합니다!
Gustavo Maciel

5

지수 시스템을 활용하여 원하는 것에 가깝게 접근 할 수 있습니다.

x를 1- (rnd ^ value) (rnd가 0과 1 사이라고 가정)와 같은 것으로 만들면 사용하는 것에 따라 왼쪽에서 오른쪽으로 기울이기의 몇 가지 동작이 나타납니다. 값이 높을수록 분포가 더 왜곡됩니다

온라인 그래프 도구를 사용하여 다른 방정식을 배치하기 전에 제공하는 동작에 대한 대략적인 아이디어를 얻거나 취향에 맞는 스타일에 따라 입자 시스템에서 직접 방정식을 피들 링 할 수 있습니다.

편집하다

파티클 당 CPU 시간이 매우 중요한 파티클 시스템과 같은 경우 Math.Pow (또는 해당 언어)를 직접 사용하면 성능이 저하 될 수 있습니다. 더 많은 성능이 요구되고 런타임에서 값이 변경되지 않는 경우 x ^ 2 대신 x * x와 같은 기능으로 전환하는 것이 좋습니다.

(분수 지수는 더 문제가 될 수 있지만 근사 함수를 만드는 좋은 방법을 생각해 낼 수있는 것보다 수학 배경이 강한 사람은 아마도)


1
그래프 프로그램을 사용하는 대신 베타 배포판을 특수한 경우로 플로팅 할 수 있습니다. 주어진의 value경우 이것은 Beta (value, 1)입니다.
Neil G

고마워. 나는 일부 그래프를 플로팅하려고했는데 원하는 곳으로 갈 수 있다고 생각합니다.
didito

@Neil G "베타 배포"에 대한 팁에 감사드립니다-흥미롭고 유용하게 들립니다 ... 나는 그 주제에 대해 약간의 연구를 할 것입니다
didito

3

당신이 찾고있는 용어는 Weighted Random Numbers, 내가 본 알고리즘의 대부분은 삼각 함수를 사용하지만 효율적인 방법을 찾았다 고 생각합니다.

랜덤 함수에 대한 승수 값을 보유하는 테이블 / 배열 / 목록 (무엇이든)을 만듭니다. 직접 또는 프로그래밍 방식으로 작성하십시오 ...

randMulti= {.1,.1,.1,.1,.1,.1,.2,.2,.3,.3,.9,1,1,1,} 

그런 다음 random무작위로 선택한 배수 randMulti와 마지막으로 최대 분포 값 을 곱 하십시오 ...

weightedRandom = math.random()*randMulti[Math.random(randMulti.length)]*maxValue

나는 이것이 sqrt또는 다른 계산적으로 복잡한 함수를 사용하는 것보다 훨씬 빠르며 더 많은 사용자 정의 그룹화 패턴을 허용 할 것이라고 믿습니다 .


2
메모리를 희생 할 수 있으면 미리 계산 된 100 개의 값이있는 테이블이 더 빠릅니다 (그리고 약간 더 정확합니다). 사용자가 전체 버전과 사전 계산 된 버전을 구별 할 수 있을지 의심됩니다.
Daniel Blezek

@Daniel은 더 빠를 것이지만 100 개의 임의 값을 사용하면 반복되는 패턴을 쉽게 볼 수 있습니다.
AttackingHobo

반복되는 패턴이 있다고해서 이것이 무작위가 아님을 의미하지는 않습니다. 무작위성의 본질은 예측할 수 없다는 것입니다. 문자 그대로 패턴이 없을 것이라고 예측할 수없고, 최소한 짧은 시간 동안 패턴이있을 것으로 예측할 수 없다는 것을 의미합니다. 몇 가지 테스트를 수행해야하지만 다른 시드를 사용하여 여러 테스트가있는 패턴을 찾으면 의사 난수 생성 알고리즘을 검토해야 할 수 있습니다.
랜돌프 리차드슨

그 트릭에 대한 @AttackingHobo thx. 나는 LUT의 사용을 좋아한다. 공식은 이해하기 매우 쉽습니다. 나는 전에 이런 식으로 생각하지 않았다. 나무를 위해 나무를 보지 않으면 ... :) 또한 반복 패턴을 피해야하지만이 경우에는 어쩌면 인식되지 않을 것이라고 생각합니다. 여전히 모든 값을 미리 계산하면 시각적 경험이 손상 될 수 있습니다. 어쨌든, 이것이 무작위성 주제에 대해 고려해야 할 요소라는 것을 상기시켜주었습니다.
didito

가중 "랜덤 숫자"라는 용어를 가져 주셔서 감사합니다!
didito

2

나는 당신이 요구하는 것은 제곱근 함수를 사용하여 얻은 분포라고 생각합니다.

[position] = sqrt(rand(0, 1))

이는 [0, 1]위치에 대한 확률이 해당 위치와 같은 단일 차원 필드 에 분포, 즉 "삼각 분포"를 제공합니다.

대체 제곱근없는 생성 :

[position] = 1-abs(rand(0, 1)-rand(0, 1))

최적의 구현에서 제곱근은 분기가없는 몇 가지 곱셈 및 합 명령입니다. ( http://en.wikipedia.org/wiki/Fast_inverse_square_root 참조 ) 이 두 기능 중 더 빠른 기능은 플랫폼 및 랜덤 생성기에 따라 다를 수 있습니다. 예를 들어 x86 플랫폼에서는 랜덤 생성기에서 예측할 수없는 몇 가지만 가져와 두 번째 방법을 느리게 만듭니다.


위치의 확률은 위치와 같지 않습니다 (수학적으로 불가능합니다-사소하게도, 함수의 영역과 범위는 0.50과 0.51을 모두 포함합니다). ( en.wikipedia.org/wiki/Triangular_distribution )

1
sqrt는 몇 가지 흥미로운 패턴을 제공하지만, 파티클 시스템은 일반적으로 파티클 당 매우 CPU 라이트 여야하므로 가능한 경우 제곱근 (계산 속도가 느린)을 피하는 것이 좋습니다. 때로는 사전 계산만으로 도망 갈 수도 있지만 시간이 지남에 따라 파티클이 눈에 띄는 패턴을 만들 수 있습니다.
Lunin

1
@Joe Wreschnig, Wikipedia 기사를 직접 작성하여 a = 1, b = 1, c = 1을 생성 공식으로 읽었고 내 게시물에서 공식을 얻었습니다.
aaaaaaaaaaaa

3
@Lunin, 왜 답에 지수를 넣었을 때 제곱근에 대해 불평합니까?
aaaaaaaaaaaa

1
@Lunin : 퍼포먼스 이론은 상당히 무시 된 분야입니다. 사람들은 대략 30 년 전에 ALU가 비싸고 느 렸을 때 어디에서 올바른지를 알고 있다고 생각합니다. 아주 느린 산술 함수라는 것을 발견 한 지수 함수조차도 성능이 크게 저하되는 경우는 거의 없습니다. 분기 (if 문 사용) 및 캐시 미스 (현재 캐시에없는 데이터 조각 읽기)는 일반적으로 성능이 가장 높은 비용입니다.
aaaaaaaaaaaa

1

베타 배포판을 사용하십시오.

  • 베타 (1,1)는 평평합니다
  • 베타 (1,2)는 선형 그래디언트입니다
  • 베타 (1,3)는 2 차입니다

기타

두 모양 매개 변수는 정수일 필요는 없습니다.


당신의 도움을 위해 thx. 위에서 언급했듯이 베타 배포판은 흥미롭게 들립니다. 그러나 나는 위키 백과 페이지의 내용을 아직 이해할 수 없습니다. 또는 수식 / 코드. 글쎄, 나는 지금 더 조사 할 시간이 없다. 글쎄, 나는 먼저 그것을 통과 한 다음 내 자신의 단순화 된 버전을 작성해야한다고 생각합니다.
didito

1
@didito : 그렇게 어렵지 않습니다. uniform_generator()통화를로 바꾸십시오 gsl_ran_beta(rng, a, b). 다음을 참조하십시오 : gnu.org/software/gsl/manual/html_node/…
Neil G

힌트를위한 thx. 나는 GSL을 사용하지 않지만 (실제로 그것에 대해 들어 본 적이 없다), 좋은 전화. 나는 소스를 확인합니다!
didito

@didito :이 경우 Lunin의 솔루션을 사용합니다. 행운을 빕니다.
Neil G

0

랜덤 제너레이터의 속도에 따라 더 간단하게 두 값을 생성하여 평균을 내릴 수 있습니다.

또는, 더 간단하고, X는 먼저 RNG의 결과입니다 double y = double(1/x);, x = y*[maximum return value of rng];. 이것은 숫자가 지수 적으로 낮은 숫자에 가중됩니다.

더 많은 값을 생성하고 평균화하여 값이 중심에 가까워 질 가능성을 높입니다.

물론 이것은 표준 벨 커브 분포 또는 "폴딩 된"버전에서만 작동하지만 빠른 제너레이터를 사용하면 sqrt와 같은 다양한 수학 함수를 사용하는 것보다 더 빠르고 간단 할 수 있습니다.

주사위 종 곡선에 대한 모든 종류의 연구를 찾을 수 있습니다. 실제로 Anydice.com은 다양한 주사위 굴림 방법에 대한 그래프를 생성하는 좋은 사이트입니다. RNG를 사용하고 있지만 결과는 전제와 동일합니다. 따라서 배포하기 전에 배포판을 보는 것이 좋습니다.

* 또한 축을 취하고 평균 결과를 뺀 다음 축을 추가하여 축을 따라 결과 분포를 "접습니다". 예를 들어, 더 낮은 값이 더 일반적이고 15가 최소값이되고 35가 최대 값이 20 인 범위를 원한다고 가정합니다. 따라서 20의 범위 ( 원하는 범위의 두 배), 20을 중심으로 한 벨 커브를 줄 것입니다 (끝에서 5를 빼서 범위를 20에서 40으로, 15에서 35로 이동). 생성 된 숫자 X와 Y를 가져옵니다.

최종 번호,

z =(x+y)/2;// average them
If (z<20){z = (20-z)+20;}// fold if below axis
return z-5;// return value adjusted to desired range

최소값이 0이 아니라면 대신이 작업을 수행하십시오.

z= (x+y)/2;
If (z<20){z = 20-z;}
else {z = z - 20;}
return z;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.