2010-12-02 67 views
2

我遇到了浮点算术的一些问题,并不准确。我试图根据加权公式计算得分,其中每个输入变量的重量大约是下一个重要变量的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 2010-12-02 20:20:51

+1

你可以使用双。限制自己漂浮的限制效用是有限的(除了存储空间,除非你处于非常特殊的情况下不应该是个问题)。 – 2010-12-02 20:24:14

回答

4
  1. 你是不是输出整个值,使用cout << setprecision(number_of_digits) << score1 << endl;
  2. 多少有效的数字,你在你的分数计算需要什么?
+0

谢谢,设置更高的精度我现在看到正确的值,这是否意味着我的代码实际上按照预期的方式工作,比较像'if(score1 nus 2010-12-02 20:25:45

+0

这样的分数那么,是的,比较两个浮点数将比较它们的值。 – 2010-12-02 20:31:02

3

我想用一百年我输入相乘,然后使用一个int(因为这将是足够的,我认为准确),但我怀疑这是最好的解决方案

鉴于你已经展示的价值观,我会说它是。

+0

实际上,将输入乘以100将不起作用 - 即使输入是整数,也不是所有计算都会导致整数。您必须将输入乘以10000或1000000并更改计算中的常量。 – 2010-12-02 20:21:47

1

http://ideone.com/qqTB3向您显示差异不会丢失,但实际上与您预期的一样大(达到浮点精度,即双精度值的15位十进制数)。

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 

精度应保持这些值:
但是,当你打印出来双打的默认精度为3位小数。

std::cout << 107.8878; 
> 107.888 

所以设定精度:

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