2010-12-02 8 views
2

Im 부동 소수점 산술로 인해 일부 문제가 발생했습니다. 저는 모든 입력 변수가 다음 중요한 변수의 약 20 배에 달하는 가중치 공식을 기반으로 점수를 계산하려고합니다. 그러나 입력은 실수이므로 결과를 저장하기 위해 double을 사용하게되었습니다. 아래 코드는 E1과 E2의 차이를 잃어 버리는 문제가 있습니다.C++에서 부동 소수점 연산의 반올림 문제를 해결하는 방법은 무엇입니까?

이 코드는 성능에 민감하므로이 문제에 대한 효율적인 대답을 찾아야합니다. 나는 입력을 수백 배로 늘린 다음 int를 사용하여 생각했다. (생각하면 충분히 정확할 것이다.) 그러나 이것이 최상의 해결책이라는 것을 의문시한다.

#include <iostream> 

int main() 
{ 
    double score1, score2; 
    float a = 2.75 ; 
    float b = 5.25 ; 
    float c = 5.25 ; 
    float d = 2.75 ; 
    float E1 = 3 ; 
    float E2 = 6 ; 

    score1 = 20 * b - 1 * a + 0.05 * d /* - 0.0025 * c*/ + 0.0001 * E1 ; 
    score2 = 20 * b - 1 * a + 0.05 * d /* - 0.0025 * c*/ + 0.0001 * E2 ; 

    std::cout << score1 << std::endl; 
    std::cout << score2 << std::endl; 

    std::cin.get(); 
    return 0; 
} 

//ouputs: 
//102.388 
//102.388 
+0

부동 소수점이 제한되어, 그것에 대해 많은 정보가있다. – Drakosha

+1

두 번 사용할 수 있습니다. 아주 특정한 상황에 있지 않는 한 저장 공간과는 별도로 플로팅을 제한하는 데에는 제한된 유틸리티가 있습니다. –

답변

4
  1. ,
  2. 얼마나 많은 유효 숫자 당신이 당신의 점수 계산에 필요합니까 cout << setprecision(number_of_digits) << score1 << endl; 사용할 수 있습니까?
+0

감사합니다, 더 높은 정밀도 설정 지금 올바른 값을 볼 수 있습니다. 즉,'if (score1 nus

+0

두 개의 부동 소수점을 비교하면 해당 값을 비교할 것입니다. –

+0

미안하지만, 만약 당신이 바보 같으면 디버깅 로그에서 잘못된 값을 보게되면, 가장 먼저 생각하는 것은 그들이 실제로 잘못되었다는 것입니다. 특히 이것이 당신이 찾고있는 버그를 설명 할 수 있다면 더욱 그렇습니다. – nus

3

나는 (그 정도로 내가 생각하는 정확한 것 때문에) int를 사용하여 다음 백으로 내 입력을 곱한 생각,하지만 난 그게 최선의 해결책

주어진 의심 당신이 보여준 가치들, 나는 그렇다고 말할 수 있습니다. 당신이 전체 값을 출력하지 않습니다

+0

실제로 입력에 100을 곱하면 작동하지 않습니다. 입력이 정수인 경우에도 모든 계산 결과가 정수가되는 것은 아닙니다. 입력 값에 10000 또는 1000000을 곱하고 계산에서 상수를 변경해야합니다. –

1

http://ideone.com/qqTB3 당신이 그 차이를 잃어 버리지는 않았지만 실제로 예상했던 것만 큼 큰 것을 보여줍니다 (부동 소수점의 정확도는 두 자리의 십진수 15 자리).

+0

+ 1 나를 ideone.com에 소개합니다. – nus

1

이 코드에 무슨 일이 일어나고 있는지 볼 수 있습니다 :

score1 = 20 * b - 1 * a + 0.05 * d /* - 0.0025 * c*/ + 0.0001 * E1 ; 

// Multiplication division happens first: 

float tmp1 = static_cast<float>(20) * b;  // 20 cast to float. 
float tmp2 = static_cast<float>(1) * a;  // 1 cast to float. 
double tmp3 = 0.05 * static_cast<double>(d); // d converted to double as 0.05 is double 
double tmp4 = 0.0001 * static_cast<double>(E1);// E1 cast to double as 0.0001 is double 

// Addition and subtraction now happen 
float tmp5 = tmp1 - tmp2; 
double tmp6 = static_cast<double>(tmp5) + tmp3; // tmp5 cast to double as tmp3 is a double. 
double tmp7 = tmp6 + tmp4; 
score1  = tmp7; 

우리는 우리의 머리에서이 작업을 수행하는 경우 :

tmp1 = 105.0 
tmp2 = 2.75 
tmp3 = 0.1375 
tmp4 = 0.0003 
tmp5 = 107.75 
tmp6 = 107.8875 
tmp7 = 107.8878 
정밀도는 그 값을 유지해야

:
하지만 당신은 밖으로 인쇄 할 때 double 형의 디폴트 정밀도는 소수점 이하 3 자리입니다.

std::cout << 107.8878; 
> 107.888 

그래서 정밀도를 설정 : 즉 그것은 모든 부동 소수점 숫자를 표현 할 수없는,

std::cout << std::setprecision(15) << 107.8878 << "\n"; 
> 107.8878 
+0

흠, 그다지 좋지 않습니다 ... 더 좋은 방법이 있습니까? – nus

+0

당신은 그것이 매우 perfomant (그것은 단어가 아니에요) 보이지 않는 것을 의미합니까? 이것은 컴파일러가 코드를 생성하는 방법입니다.임시 변수는 아마도 레지스터가 될 것이고 옵티마이 저는 조작의 순서를 (어느 정도까지) 교환 할 수 있지만 이것은 기본 코드가 할 일입니다. –

+0

내가 보여 주려고했던 것은 대부분의 작업이 복식에서 수행된다는 것입니다. 따라서 매우 구체적인 공간 요구 사항이 없으면 변수가 두 배가되어야합니다. –

관련 문제