부동 소수점 숫자의 해상도가 원점에서 더 감소하는 이유는 무엇입니까?


19

내 OpenGL 장면에는 원점에서 엄청나게 먼 거리에 위치한 객체가 있습니다. 이 물체를보고, 주위로 카메라를 이동 / 회전 / 줌하면 '지 터링'됩니다. 즉, 객체를 구성하는 꼭짓점은 가상의 3D 그리드 점 주위에 스냅하는 것처럼 보입니다. 부동 소수점 정밀도 (OpenGL 및 기타 거의 모든 것이 사용하는)를 사용하여 저장할 수있는 정보의 양 때문에 이것이 일반적인 문제라는 것을 읽었습니다. 그래도 이런 일이 발생 하지 않습니다 .

솔루션을 검색 할 때 매우 간단한 '플로팅 원점'수정을 발견했으며 작동하는 것 같습니다. 물체가 동일한 상대 위치에 있도록 모든 것을 변형하지만 내 카메라가 보는 것은 원점에 가깝습니다. http://floatingorigin.com/ 에서 설명을 찾았 지만 따라갈 수 없었습니다.

그래서 ... 누가 내 장면을 원점에서 아주 멀리 (예 : 천만 단위) 배치하면 내가 관찰 한 불규칙한 동작이 발생하는지 설명 할 수 있습니까? 또한 왜 원점에 가깝게 옮기면 문제가 해결됩니까?


4
그렇지 않으면 고정 소수점 숫자 가되기 때문 입니다. 긴장 론적 질문, 이것.
MSalters

1
'부동 소수점'이 실제로 무엇을 의미하는지 이해하는 경우에만 해당됩니다.
Kylotan

답변:


26

이것은 부동 소수점이 컴퓨터에서 표현되는 방식으로 인한 것입니다.

정수는 매우 간단하게 저장됩니다. 각 단위는 셀 수있는 숫자와 마찬가지로 "이전"과는 정확히 "하나"입니다.

부동 소수점 숫자를 사용하면 정확히 그렇지 않습니다. 대신, 몇 비트는 지수를 나타내고 나머지는 가수 또는 소수 부분 으로 알려진 것을 나타내며 , 그 결과 지수 부분 (암시 적으로 2 ^ exp)에 의해 다중화되어 최종 결과를 제공합니다.

여기 비트의 시각적 설명.

이 지수는 숫자가 커지면 정밀도가 WANE로 시작하는 비트의 실제 부분이기 때문에 정확하게 나타납니다.

이것이 실제로 작동하는 것을보기 위해, 요점을 모르는 상태에서 가짜 부동 소수점 표현을 해봅시다 : 2와 같은 작은 지수를 취하고 테스트 할 분수 부분을 수행하십시오 :

2 * 2 ^ 2 = 8

3 * 2 ^ 2 = 12

4 * 2 ^ 2 = 16

...기타.

이 숫자는 지수 2에서만 크게 멀지 않습니다. 그러나 이제 지수 38을 사용해 봅시다.

2 * 2 ^ 38 = 549755813888

3 * 2 ^ 38 = 824633720832

4 * 2 ^ 38 = 1099511627776

우와, 지금 큰 차이!

이 예는 구체적으로 VERY NEXT COUNTABLE로 이동하지는 않지만 (비트 수에 따라 다음 분수 부분이 됨) 숫자가 커지면 정밀도 손실을 보여줍니다. 플로트의 "다음으로 계산 가능한"단위는 작은 지수로 매우 작고 큰 지수로 매우 큽니다. 반면 정수에서는 항상 1입니다.

float origin 메서드가 작동하는 이유는 잠재적으로 큰 지수 부동 소수점 수를 모두 작은 지수로 축소하여 "다음 개수"(정밀도)가 매우 작고 행복 할 수 있기 때문입니다.


당신이 제공 한 예는 정말 예시 적입니다. :)
Pris

3
올바른 트랙에서 부동 소수점이 실제로 작동하는 방식에 더 가까운 예제를 사용했으면합니다. 가수를 지수로 올리지 않습니다. 가수 * 2 ^ 지수입니다.
Nathan Reed

3
당신 말이 맞아요. 내가 무슨 생각을했는지 모르겠습니다. 내 답변을 수정했습니다.

1
@ScottW 멋진 편집! +1
Nathan Reed


8

분야에서 고전을 제기해야합니다 모든 컴퓨터 과학자는 부동 소수점 숫자에 대해 알아야 할 사항 .

그러나 그것의 요지는 단일 (이중) 정밀 부동 소수점 숫자가 부호를 나타내는 1 비트, 기수 2의 8 비트 (11 비트)를 나타내는 32 비트 (64 비트) 이진수와 어떻게 관련이 있습니까? , 23 비트 (52 비트) 유효 값 (괄호는 복식 값)입니다.

즉, 단 정밀도로 나타낼 수있는 가장 작은 양수는 0.0000000000000000000001 x 2 -127 = 2-22 x 2-127 = 2-149 ~ 1.40 x 10-45 입니다.

0.0000000000000000000010 X 2 : 다음 양수는 더블 -127 = 2 -148 ~ 2.80 × 10 -45 하고 다음 번호는 이전 두 0.0000000000000000000011 × 2의 합이다 -127 = 3 × 2 -149 ~ 4.2 - 45 .

0.1111111111111111111111 X 2 :이 때까지 동일한 상수 차이가 계속 증가 -127 = 2 -126 - 2 149 ~ 1.17549435 × 10 -38 - 0.00000014 × 10 -38 = 1.17549421 × 10 -38

이제 일반 숫자 (유의의 첫 번째 숫자는 1)에 도달했습니다. 구체적으로 1.0000000000000000000000 x 2 -126 = 2-126 = 1.17549435 x 10-38 이고 다음 숫자는 1.0000000000000000000001 x 2 -126 = 2-126입니다. (1 + 2-22 ) = 1.17549435 x 1.00000023.


2

부동 소수점 숫자가 원점에서 더 정확하지 않은 이유는 부동 소수점 숫자가 큰 숫자를 나타낼 수 있기 때문입니다. 이것이 수행되는 방식은 "부동 소수점"이라는 용어를 빌려줍니다. 각 지수에 대해 거의 같은 수를 갖도록 취할 수있는 가능한 값 (비트 길이에 의해 결정됨)을 분할합니다. 따라서 각 지수 범위에서 2 ^ 23 다른 값을 취할 수 있습니다. 이 지수 범위 중 하나는 1-2 [2 ^ 0 ~ 2 ^ 1]이므로 1에서 2까지의 범위를 2 ^ 23의 다른 값으로 나누면 많은 정밀도가 가능합니다.

그러나 [2 ^ 10에서 2 ^ 11] 범위를 2 ^ 23의 다른 값으로 나누면 각 값 사이의 간격이 훨씬 큽니다. 그렇지 않은 경우 23 비트로는 충분하지 않습니다. 모든 것은 타협입니다. 실수를 나타내려면 무한한 수의 비트가 필요합니다. 응용 프로그램이 더 큰 값에 대해 낮은 정밀도로 벗어날 수있는 방식으로 작동하고 실제로 큰 값을 나타낼 수있는 이점이 있으면 부동 소수점 표현을 사용합니다.


7 년 후의 추가 검토를 통해 여기에 메모를 작성하면 ... 내 예에서 제 숫자는 특히 잘 선택되지 않았습니다. 그러나 전반적인 포인트는 유효합니다.
Steven Lu

1

부동 소수점 정밀도의 작동 방식에 대한 특정 예를 제공하는 것은 약간 어려울 수 있습니다. 다른 답변을 보완하기 위해 여기에 하나가 있습니다. 세 자리의 가수와 한 자리의 지수를 가진 십진 부동 소수점 숫자 가 있다고 가정 해 봅시다 .

가수 × 10 지수

지수가 0이면 0-999 범위의 모든 정수를 정확하게 표현할 수 있습니다. 1이면 기본적으로 해당 범위의 모든 요소에 10을 곱한 것이므로 0-9990의 범위를 갖습니다. 그러나 이제 세 자리의 자릿수 만 있기 때문에 10의 배수 만 정확하게 표현할 수 있습니다. 지수가 최대 9 일 때, 표현 가능한 정수 쌍의 차이는 10 억 입니다. 말 그대로 범위의 정밀도를 거래하고 있습니다.

이진 부동 소수점 숫자와 동일한 방식으로 작동합니다. 지수가 1 씩 올라갈 때마다 범위가 두 배로 증가 하지만 해당 범위 내의 표현 가능한 값의 수는 절반으로 줄어 듭니다 . 이것은 분수의 경우에도 적용되며 문제의 원인입니다.


0

일반적으로 분해능에 지수 값 (2 ** 지수 부분)을 곱하여 분해능이 악화됩니다.

josh의 의견을 인정하면서 위의 내용은 간결한 진술에 답을 넣는 것입니다. 물론, http://floatingorigin.com/ 에 표시하려고 시도한 것처럼 이것은 전체 솔루션으로 시작되고 있으며 프로그램은 정밀 파이프 라인 또는 코드의 다른 부분에서 여러 곳에서 지터를 일으킬 수 있습니다. .


이것은 다른 답변에 아직없는 것을 추가하지 않습니다.

사실 : 나는 한 줄로 답변을 설명 할 수 있다는 것을 깨달았고 누군가 간결한 답변이 유용하다고 생각했습니다.
Chris Thorne

-1

OpenGL 깊이 버퍼는 선형이 아닙니다 . 더 멀리 갈수록 해상도가 떨어집니다. 나는 이것을 읽는 것이 좋습니다 . 거기에서 가져온 것 (12.070) :

요약하면, 원근 분할은 본질적으로 후면 근처보다 뷰 볼륨의 정면에 더 많은 Z 정밀도를 유발합니다.

그리고 또 하나 (12.040) :

깊이 버퍼 정밀도를 심각하게 제한하는 방식으로 zNear 및 zFar 클리핑 평면을 구성했을 수 있습니다. 일반적으로 이는 0.0에 너무 가까운 zNear 클리핑 평면 값으로 인해 발생합니다. zNear 클리핑 평면이 0.0에 점점 더 가깝게 설정 될수록 깊이 버퍼의 유효 정밀도는 급격히 떨어집니다. zFar 클리핑 평면을 눈에서 더 멀리 이동하면 깊이 버퍼 정밀도에 항상 부정적인 영향을 미치지 만 zNear 클리핑 평면을 이동하는 것만 큼 극적인 것은 아닙니다.

따라서 가장 가까운 클리핑 평면을 최대한 멀리 이동하고 먼 평면을 최대한 가깝게 이동해야합니다.


-1 : 비선형 깊이 버퍼 표현의 정밀도 문제가 아니라 부동 소수점 정밀도에 관한 문제입니다.
Nathan Reed

내가보고있는 것은 깊이 버퍼링 문제 때문일 수 있습니다. OpenGL 위에 lib를 사용하여 장면을보고 있는데, 지오메트리의 크기와 위치를 설명하기 위해 카메라, 뷰 및 근거리 및 원거리 클리핑 평면을 설정한다고 가정하고 있습니다 (뷰어 이후) 도구는 장면 내용에 대한 최적의보기를 자동으로 설정하는 것 같습니다). 그러나 이것이 사실이 아닐 수도 있습니다. 나는 원래 위치를 그대로두고 클리핑 평면을 가지고 놀아보고 어떤 일이 일어나는지 보려고합니다.
Pris

2Nathan Reed : 저자는 OpenGL 장면이 있다고 썼기 때문에이 문제도있을 수 있다고 생각했습니다.
zacharmarz 2012

이 문제는 비슷하거나 관련이있을 수 있지만 깊이 버퍼 값은 부동 소수점 숫자와 호환되는 방식으로 저장되지 않습니다. 고정 소수점 형식입니다. 이로 인해 답변이 오도 될 수 있습니다.
Steven Lu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.