2011-06-30 36 views
1

我遇到了一些我从未见过的东西,并且非常想知道发生了什么。我正在试图将double加2位小数,并将该值转换为一个字符串。演员完成后,事情对我发疯。将浮点(双精度)铸造成字符串

下面是代码:

void formatPercent(std::string& percent, const std::string& value, Config& config) 
{ 
    double number = boost::lexical_cast<double>(value); 
    if (config.total == 0) 
    { 
     std::ostringstream err; 
     err << "Cannot calculate percent from zero total."; 
     throw std::runtime_error(err.str()); 
    } 
    number = (number/config.total)*100; 
    // Format the string to only return 2 decimals of precision 
    number = floor(number*100 + .5)/100; 
    percent = boost::lexical_cast<std::string>(number); 

    return; 
} 

我没有得到完全是我预料,所以我做了一些调查。我做了以下内容:

std::cout << std::setprecision(10) << "number = " << number << std::endl; 
std::cout << "percent = " << percent << std::endl; 

...并得到如下:

number = 30.63 
percent = 30.629999999999999 

我怀疑升压正在做一些有趣的事情。有没有人有任何见解?

说真的,这有多奇怪?!?我要求一个双精度的10位精度,并获得4位数字。我要求将这4位数字转换成一个字符串,并将其弄乱。到底是怎么回事?

+7

是时候另一个链接到什么每台计算机科学家应该知道关于浮点运算:http://download.oracle.com/docs/cd/E19957-01 /806-3568/ncg_goldberg.html –

+1

您的链接根本无法解决我的问题。这其实只是一种迂回的回答我的问题的方式。你会注意到Martin Beckett的回答直接回答了这个问题。 – Rico

+0

二进制的30.63的扩展是无限的,正如基数10中1/3的扩展是无限的。词法铸()做它应该是因为数字真的不是30.63。请参阅http://stackoverflow.com/questions/5016464/boostlexical-cast-conversion-double-to-string-c –

回答

1

的std ::精度设置的显著位的最大数目,以显示

在缺省浮点 表示法中,精密场 指定 有意义的最大位数总共 计数显示小数点后的那些以及那些 。请注意, 它不是最小值,因此如果 显示的数字位数小于 精度,则它不会将显示的数字填充为尾随零的 。

30.629999999999999是30.63

+0

谢谢你这个有用的答案。我没有意识到std :: precision不会显示尾随零(或9)。 – Rico

+0

@Rico - 直到我GOOGLE了这个! –

0

问题是浮点数不能准确表示任意十进制值。你看到的是浮点错误。 Boost正在准确显示您提供给它的值。

1

实际浮点表示你要求的精度十个位数,但实际的“不准确”,是进一步下跌,所以当它四舍五入到十位数字就变成了整洁30.63。您的lexical_cast将所有数字考虑在内,因此会产生精确的浮点值(可能不是您想要的精度,但它是计算机内存中内容的最精确表示)。

3

十进制数30.63不能存储在double类型的对象中。实际存储的最接近的有效双精度值是8621578536647393 * 2^-48,在十进制中,该值为30.629999999999999005240169935859739780426025390625

你可以看到,如果你做std::cout << std::setprecision(100) << "number = " << number << std::endl;