hotfix: rewrite rand_range logic - #93
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the behavior of rand_range(min, max) to align with its name by treating max as inclusive and removing the prior implicit assumptions about min == 0 / positive max. It also updates in-repo call sites to match the new inclusive contract.
Changes:
- Reimplemented
rand_range(min, max)to generate a (near) uniform distribution over an inclusive[min, max]range using rejection sampling. - Updated callers (noise generation and template selection) to pass
max - 1where they previously relied on an exclusive upper bound. - Adjusted a couple of inline comments to reflect the new range semantics.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
yandere/c/noise.c |
Updates random selection bounds to preserve the intended probabilities under inclusive rand_range. |
lib/utils.c |
Rewrites rand_range(min, max) implementation to use an inclusive range and rejection sampling. |
hhss/c/replace.c |
Updates random indexing into arrays to account for inclusive rand_range. |
hhss/c/prelex.c |
Updates random selection index bounds to match inclusive rand_range. |
|
@lshqqytiger It'd be greatly appreciated if you could review the last commit. |
| /* implicit integer promotion happens */ | ||
| /* INT_MAX - INT_MIN == UINT_MAX */ | ||
| if ((unsigned int) max - min > RAND_MAX) | ||
| VERR("range too large to handle!" | ||
| " max - min must <= %d (RAND_MAX)," | ||
| " but given min=%d, max=%d", min, max); |
There was a problem hiding this comment.
min, max로 양수만 받을거면 주석으로 남기죠
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
There was a problem hiding this comment.
@lshqqytiger min, max가 음수인 경우도 생각하긴 했어요
예를들어 (min, max 둘다 int) min = -10, max = -5 라고 하고
uint의 최댓값을 2^32 = 4,294,967,296 이라고 하면
(unsigned int) max - min > RAND_MAX
여기서 max가 uint로 캐스팅되니까 -5 mod 2^32 = 4,294,967,291 되고
max가 uint가 되었고 뺄셈연산을 해야하므로 암시적 정수 형변환에 의해 min도 암시적으로 uint로 캐스팅
따라서 min = -10 mod 2^32 = 4,294,967,286
따라서 max - min = 4,294,967,291 - 4,294,967,286 = 5 인데
-5 - (-10) 역시 5 이므로 올바른 결과값
===
극단적으로 min = INT_MIN 이고 max = INT_MAX 라고 해도
INT_MAX는 양수니까 uint로 캐스팅해도 값은 그대로 2,147,483,647
그러나 INT_MIN은 음수이므로 uint로 암시적 캐스팅되면 -2,147,483,648 mod 2^32 = 2,147,483,648
따라서 max - min = 2,147,483,647 - 2,147,483,648 = -1 가 됩니다
그러나 uint간의 연산인데 결과값이 음수이므로, 그 결과는 -1 mod 2^32 = 4,294,967,295 가 됩니다
그런데 2,147,483,647 - (-2,147,483,648) 역시 4,294,967,295 이므로 올바른 결과값이 나옵니다
===
max도 양수 min도 양수인 경우는 max >= min 이므로 max - min 은 항상 양수
===
max가 음수인데 min이 양수인 경우는, 음수는 항상 양수보다 작으므로 max < min 이고 이는 전제조건인 max >= min을 만족시키지 못합니다
===
즉
음수-음수 => fine
양수-음수 => fine
양수-양수 => fine
음수-양수 => 성립x
어떤 경우든 mod 연산이 어떻게 잘 일어나가지고 원하는 결과가 마법처럼 나오는거같다고 생각합니다
예를들어 max = 10 이고 min = -5 라고 해도, -5를 uint로 캐스팅하면 4,294,967,291 니까 10 - 4,294,967,291 이고 이걸 계산하면 -4,294,967,281 인데 여기 다시 mod 2^32를 하면 15 니까 10-(-5)=15와 일치
결론적으로 지금 코드는 괜찮은거같은데 왜 코파일럿이 항의하는지 잘 몰겠네요
There was a problem hiding this comment.
@copilot The range-size check does not reject valid ranges even if negative min is wrapped.
There was a problem hiding this comment.
Confirmed — the unsigned arithmetic is correct for all valid inputs. @logic-finder's analysis covers every case: the wrap-around on both operands cancels out and the subtraction yields the mathematically correct range size regardless of the sign of min or max (given the precondition min <= max).
Separately, there was a genuine bug in the same block: the VERR format string had three %d specifiers but only min and max were passed — RAND_MAX was missing, causing undefined behavior. Fixed in the latest commit.
There was a problem hiding this comment.
깜빡하고 RAND_MAX를 추가한다는걸 놓쳤네
|
@lshqqytiger seems everything is done. |
|
@lshqqytiger Could you please approve this PR so that I can merge it? |
|
Copilot이 push한건 제 commit으로 쳐서 제 리뷰로 머지가 안 됩니다 |
For example, The current
rand_range(0,6)returns a value between [0,5]. However, this result is confusing in that it contradicts the function name.Also, the current implementation seems to make an implicit expectation that
minshould be zero andmaxshould be greater than zero. This also contradicts the function name.From these reasons, I've modified the logic of the function and its usage across the files.