음수 좌표는 두 곳에서 청크 계산을 깨뜨린다, 한 곳이 아니라
절단 나눗셈은 블록 −1을 청크 −1이 아닌 청크 0에 넣고, 일반 %는 청크 내 오프셋을 15가 아닌 −1로 만든다. 둘 다 틀렸고, 둘 다 스폰 서쪽으로 가기 전까지는 맞아 보인다.
모든 청크 계산은 양수 사분면에서는 자명하고 나머지 세 사분면에서는 틀린다. 잘못되는 곳은 정확히 두 곳이며, 서로 독립적이고, 둘 다 그럴듯해 보이는 답을 내놓는다.
두 가지 연산
chunk = floor(block / 16) not trunc(block / 16)
offset = ((block % 16) + 16) % 16 not block % 16
지역 좌표는 같은 쌍을 한 단계 위로 올린 것으로, 16 대신 32를 쓴다:
region = floor(chunk / 32) -> r.<x>.<z>.mca
regionOff = ((chunk % 32) + 32) % 32
따라서 지역은 32 × 32 청크, 즉 512 × 512 블록이다.
각각이 물어뜯는 지점
나눗셈. 대부분의 언어는 0 방향으로 절단하고, floor는 음의 무한대 방향으로 내림한다. 양수에서는 둘이 일치하고, 정확한 배수가 아닌 모든 음수에서는 어긋난다:
- 블록
−1→floor(−1/16) = −1✓, 그러나trunc(−1/16) = 0✗
블록 −1은 원점에서 한 블록 서쪽이며 청크 −1에 속한다. 절단은 이를 블록 +1과 나란히 청크 0에 넣는다. 모든 음수 청크 인덱스가 하나씩 너무 높게 나온다.
나머지. JavaScript, Java, C 및 대부분의 다른 언어에서 %는 왼쪽 피연산자의 부호를 유지한다:
- 블록
−1→ 올바른 오프셋15, 그러나−1 % 16 = −1✗
오프셋 −1은 너비 16인 청크 내부의 위치가 전혀 아니다. 이 값으로 블록 배열을 인덱싱하면 예외가 발생하거나 조용히 잘못된 셀을 읽는다.
구체적인 예시
한 축에서 블록 −1290:
| 단계 | 올바름 | 순진한 계산 |
|---|---|---|
| 청크 | floor(−1290/16) = −81 | trunc = −80 ✗ |
| 청크 내 오프셋 | 6 | −1290 % 16 = −10 ✗ |
| 지역 | floor(−81/32) = −3 | trunc = −2 ✗ |
| 지역 내 오프셋 | 15 | −81 % 32 = −17 ✗ |
네 개의 값, 네 개의 오답, 어느 것도 명백히 깨져 보일 만큼 범위를 벗어나지 않는다. 지역 −3은 청크 −96부터 −65까지 걸치며, 청크 −81은 그 시작에서 15만큼 들어간 위치다 — 이는 교정된 나머지가 돌려주는 값과 정확히 일치한다.
네더 변환은 한 방향으로 손실이 있다
오버월드에서 네더로 갈 때는 8로 나누며, 역시 내림한다:
netherX = floor(overworldX / 8)
돌아올 때는 정확한 위치에 8을 곱하므로, 네더 블록 125 전체가 그 블록 안 어디에 서 있느냐에 따라 1000–1007 어딘가로 되돌아간다. 이는 블록 좌표에 대해 왕복이 아니다. floor는 나머지를 버린다:
- 오버월드
1000→ 네더125→ 다시1000✓ - 오버월드
1007→ 네더125→ 블록 좌표는1000라고 말한다 ✗ — 일곱 블록 부족
오차는 축당 0에서 7 블록이며, 따라서 X에서 최대 7, Z에서 최대 7이 동시에 발생할 수 있다. 이것이 정밀한 포털 연결에 네더 좌표를 다시 유도하는 대신 적어 두어야 하는 이유의 전부다: 한 번 나누고 나면, 그것이 나온 오버월드 위치는 더 이상 복원할 수 없다.
네더 허브에서는 이것이 좀처럼 문제되지 않는다 — 7 블록은 포털 자체의 포획 반경 안이다. 서로의 트래픽을 가로채지 않아야 하는 두 포털을 연결할 때는 매우 중요하다.
음수 오버월드 좌표는 익숙한 방식으로 상황을 더 나쁘게 만든다: 오버월드 −1는 네더 floor(−1/8) = −1를 주지만, 절단은 0를 주어 축의 반대편으로 보낸다.