2012-01-17 3 views
3

공을 상자에 넣는 기능을합니다. 상자의 각면에 맞을 수있는 볼의 수를 계산하는 코드는 아래에 있습니다. 볼이 큐브처럼 서로 맞춰져 있다고 가정합니다. 나는 이것이 최적의 방법이 아니라는 것을 안다.C에서 이중 절단 및 수학에 문제가 있습니다

나를위한 문제는 내가 4.0000000 * 4.0000000 * 2.000000과 같은 숫자를 얻지 만, 제품이 32. 대신에 32. 31 무엇입니까 ??

두 가지 추가 사항이 오류는 최적 변 길이에 도달 한 경우에만 발생합니다. 예를 들어, 측면 길이가 12.2, 상자 두께가 0.1, 볼 반경이 1.5입니다. 이것은 정확히 4 개의 볼이 그면에 맞도록 유도합니다. int로 캐스팅하지 않으면 작동하지만 int로 캐스팅하면 앞에서 설명한 오류 (32 대신 31)가 발생합니다. 또한 인쇄면은 측면 길이가 최적 일 경우 한 번만 실행되지만 그렇지 않은 경우 두 번 실행됩니다. 그게 무슨 뜻인지 모르겠다.

double ballsFit(double r, double l, double w, double h, double boxthick) 
{ 
double ballsInL, ballsInW, ballsInH; 
int ballsinbox; 

ballsInL= (int)((l-(2*boxthick))/(r*2)); 
ballsInW= (int)((w-(2*boxthick))/(r*2)); 
ballsInH= (int)((h-(2*boxthick))/(r*2)); 
ballsinbox=(ballsInL*ballsInW*ballsInH); 
printf("LENGTH=%f\nWidth=%f\nHight=%f\nBALLS=%d\n", ballsInL, ballsInW, ballsInH, ballsinbox); 
return ballsinbox; 
} 
+0

4.0 * 4.0 * 2.0의 결과는 실제로 32.0이어야하지만 제한된 정밀도와 반올림에 대해서는'(l- (2 * boxthick))/(r * 2)'가 실제로 4.0을 얻고 3.9999999가 아닌 것을 누구도 보장하지 않습니다. 부동 소수점 숫자의 오류. –

답변

6

근본적인 문제는 부동 소수점 연산이 정확하지 않다는 점입니다.

예를 들어, 문제가되는 예제에서 두께 값으로 언급 한 숫자 0.1은 정확히 double으로 표시 할 수 없습니다. 변수에 0.1을 할당하면 근사값이 0.1로 저장됩니다.

나는 What Every Computer Scientist Should Know About Floating-Point Arithmetic을 읽는 것이 좋습니다.

4.0000000 * 4.0000000 * 2.000000과 같은 숫자가 있지만 제품은 32 대신 31입니다.

피승수 (적어도 일부는)는 외관상으로는 거의 확실합니다. 정확히 4.0, 4.0 및 2.0 인 경우 해당 제품은 정확히 32.0이됩니다. 복식에서 표현할 수있는 모든 자릿수를 인쇄하면 3.99999999999 ... 등의 9 가지를 많이 볼 수있을 것이라고 확신합니다. 결과적으로 제품은 32 미만의 작은 비트입니다. 이중에-INT 변환이 단순히 소수 부분을 자르면, 그래서 당신은 물론 31

와 끝까지, 당신은 항상 계산이 정확한한다면 그들은 것보다작은 숫자를하지 않는다; 당신은 또한 당신이 예상 할 수있는 것보다 더 큰 숫자 인을 얻을 수 있습니다.

+0

+1 그게 좋은 신문이야. 나 한텐 정말 도움이 됐어. – thkala

+0

'... 모양이 맘에 들지 않습니다.': 자바에서 가장 일반적인 경우로,'Double.toString()'메서드는 가장 소수의 자리수가 가장 가까운 가장 가까운 소수로 반올림됩니다. '17.17'의 실제 가치가 무엇인지 짐작할 수 있습니까? – thkala

+0

17.1700000000000017053025658242404460906982421875 –

1

현대의 컴퓨터에서 일반적으로 사용되는 IEEE-754과 같은 고정 소수점 부동 소수점 숫자는 정확하게 모든 십진수를 나타낼 수 없습니다. 1/3은 십진수로 정확하게 표현할 수 없습니다.

예를 들어 0.10.100000000000000004... 행을 따라 이진으로 변환 될 수 있습니다. 차이는 작지만 중요합니다.

나는 계산 과정에서 정밀도를 유지하기 위해 확장 된 임의의 정밀도 산술을 사용하여 최종 결과를 double으로 다운 컨버전하여 (부분적으로) 이러한 문제를 처리하는 경우가있었습니다. 일반적으로 성능에는 눈에 띄는 저하가 있지만 IMHO 정확성은 무한히 중요합니다.

저는 최근에 정밀도와 성능면에서 좋은 결과를 얻은 here으로 표시된 고정밀 산술 라이브러리의 알고리즘을 사용했습니다.

관련 문제