4

몇 가지 UI 버튼을 사용하여 3D 모델의 변환에 영향을 미치려고합니다. 위치를 0.1 또는 -0.1 이동하십시오.float를 사용해야 할 때 부동 소수점 오류를 실제로 피하는 방법은 무엇입니까?

내 모델 위치가 3 차원 플로트이므로 값 중 하나에 0.1f를 단순히 추가하면 명백한 반올림 오류가 발생합니다. 정밀도를 유지하기 위해 BigDecimal과 같은 것을 사용할 수는 있지만, 여전히 부동 소수점에서 다시 부동 소수점으로 변환해야하며 항상 UI가 엉망인 것처럼 보이게 만드는 바보 같은 숫자가됩니다.

표시된 값은 꽤 좋지만 반올림 오류는 더 많은 편집 작업으로 만 악화되고 읽을 수있는 저장 파일을 만듭니다.

그래서 어떻게 float을 사용해야 할 때 이러한 오류를 실제로 피할 수 있습니까?

+1

.1f를 몇 번 더 더하고 빼면 큰 오류가 발생하지 않습니다. 가장 눈에 띄는 것은 원하는 결과가 네 개이지만 매우 약간 적은 것이 생성되어 정수로 변환하는 동안 세 개로 절단되는 경우처럼 한 개씩 변경됩니다. 이는 변환 전에 반올림하여 해결할 수 있습니다. 다른 오류가 발생하는 경우 다른 오류가있을 수 있습니다. 자신이 가지고있는 문제를 보여주는 예제 데이터와 코드를 보여주십시오. –

+0

가장 쉬운 것 : 0.125만큼 증가/감소. –

답변

1

Rational 클래스를 사용합니다. 많은 사람들이 있습니다 - this one이 제대로 작동해야합니다.

Rationalfloat으로 렌더링되고 하나가 분모가 gcd으로 줄어들 때 한 가지 중요한 비용이 발생합니다. 내가 게시 한 사람은 분자와 분모를 항상 완전히 축소 된 상태로 유지하며, 항상 1/10을 더하거나 뺄 때 매우 효율적이어야합니다.

This 구현은 정규화 된 (즉, 일관된 부호로) 값은 유지하지만 감소되지는 않는다.

귀하의 용도에 맞게 구현을 선택해야합니다.

2

Kahan summationpairwise summation 알고리즘은 부동 소수점 오류를 줄이는 데 도움이됩니다. Here's some Java code for the Kahan algorithm.

+2

질문은 float를 사용하여보고합니다. 두 배로 변경하면 Kahan 합계 알고리즘보다 더 많은 오류를 줄일 수 있으며 (대부분의 하드웨어에서)보다 저렴하게 오류를 줄일 수 있습니다. 그러나 어느 방법도 잘못된 결과를 잘라내어 정수로 변환하는 경우 발생하는 오류를 해결할 수 없습니다. –

-1

당신이 수레를 고수 경우

라운드 (2^n 개의 * 값)은 원하는 값에 가까운 정확한하지만 있는 수레를 사용하는 오류를 방지하기 위해 가장 쉬운 방법 * 1/2^n.

N = 4 => 0.125
N = 8 (바이트 :

N

는 비트 수의 값이 증가 정밀도로 경우

(케이스 0.1) 사용할 수있다) => 0.9765625
N = 16 (짧은) =>를 0.100006103516 ....

긴 체인 번호 이진 변환의 인공물 실수 훨씬 적은 비트를 가지고있다. 수레로

정확한, 추가 및 오프셋 오류를 소개하지 않습니다 뺄셈하지만, 비트 수는 부동 소수점 값이 보유하고보다 길지 같이 항상만큼 예측 될 것입니다.

(이상한 플로트이기 때문에) 디스플레이가 손상 될 염려가 있다면 을 사용하고 정수만 저장하십시오 (단계 증가 -1/1). 내부적으로 설정된 최종 값은

x = value * step입니다.

단계가 1만큼 증가하거나 감소함에 따라 정밀도가 유지됩니다.

+2

여기에 귀하의 의도는 무엇입니까? 이는 특정 경계 내에서 더하기 및 빼기 중 오류를 제거하지만 사용되는 단계 크기 (.100006 ...)가 원하는 단계 크기와 다르기 때문에 전체 오류가 증가합니다. 따라서 계산 된 결과는 원하는 결과와 다릅니다. 원하는 결과를 얻으려면 어떻게해야할까요? –

+0

계산 대상이 0.1 또는 0.100인지 신경 쓰지 않아도 상관 없으므로 일반적으로 중요하지 않으므로 ... 특정 경우 3D 모델이 특정 양만큼 증가 또는 감소합니다. 예 :이 트릭을 사용합니다. 왜냐하면 시작 간격과 증가 간격이 정확히 float이면 추가가 훨씬 빠르고 정확하기 때문입니다. 나는 실제로 다시 정수 값을 가지고 있고 8 단계로 1.0을 나누는 것은 부자연스럽지 않다는 것을 의미하기 때문에 0.125를 사용하도록 조언 할 것입니다. –

+0

@downvoterXYZ : 하울 보트를 주석 처리 하시겠습니까? –

0

간단한 해결책은 고정 된 정밀도를 사용하는 것입니다. 즉 원하는 10 배 또는 100 배 정수입니다.

float f = 10; 
f += 0.1f; 

8 (당신은 부동 소수점 값의 수백만을하지 않는 한) 당신이 어떤 이익을 옆 위해 double보다 더 많은 반올림 오류를 얻을로

int i = 100; 
i += 1; // use an many times as you like 
// use i/10.0 as required. 

내가 double 당신을 제공 어떤 경우에 float를 사용하지 않을된다 더 많은 정밀도와 합리적인 반올림으로 이러한 오류가 표시되지 않습니다.