float rounding error float to double conversion

时间:2014-08-22 10:53:32

标签: c++ floating-point

我有一个我现在无法改变的系统,是使用float来存储信息。

我遇到了舍入错误的问题。示例:

std::string floatToStr(float d)
{
    std::stringstream ss;
    ss << std::fixed << std::setprecision(15) << d;
    return ss.str();
}

    float val723 = 0.575f;
    std::cout << floatToStr(val723) << std::endl;

结果是

0.574999988079071

我可以用字符串处理来纠正这个问题。

std::string doubleToStr(double d, int precision)
{
    std::stringstream ss;
    ss << std::fixed << std::setprecision(precision) << d;
    return ss.str();
}

double val945 = (double)0.575f;
std::cout << doubleToStr(atof(doubleToStr(val945, 4).c_str()), 15) << std::endl;

结果是:

0.575000000000000

但这是一个很好的解决方案。有没有更好的解决方案可以在实时流程中使用? (实际上,我不需要在我的实时代码中使用它,但如果我必须使用实时代码,我会做好准备。)

Edit1:我知道我可以在float类型的小数点后使用6或7位数。

2 个答案:

答案 0 :(得分:2)

您可以使用代码打破它。 PC以二进制形式工作,0.575是必须近似的小数部分。

正确的解决方案是将浮动打印到没有比实际存储更多的数字(7),并打印其真实值而不是您认为它应包含的十进制值。

答案 1 :(得分:2)

嗯。你在小数点后面要求15位数,这就是它给你的东西。看起来有点违背抱怨!

值为float的事实意味着6个十进制数字大约是可用精度的限制(7,如果您确信几乎没有舍入错误)。要求15位小数,之后'。'向您展示了浮点数的ls位的状态,它受到舍入和表示错误的影响。

你似乎想要做的是将浮动的值显示为双倍,好到15位小数,然后你需要将浮点数的双倍版本舍入为6(或者,如果你感到勇敢)7 十进制精度数字。这与二进制到十进制转换的作用非常相似,但是您需要准备值的双重副本,以便输出。

这不是从获取值的字符串版本到6位数,并将其转换为double的一百万英里。你可以为自己建立更快的!

很遗憾,仍有问题。在'。'之后你需要15个小数。这将显示大于10.0的值的表示错误,并且可能显示1.0到10.00之间的值。例如:如果您的浮点值是(例如)57.51234f(其实际值约为57.512340545654297);下面的代码将交付575124.0 / 10000.0作为双倍,当输出给出:57.512300000000003 - 因为你要求比双必须给的大约1位数。 (对于5751.234f,同样的过程给出5751.229999999999563。)

我会仔细考虑为什么'。'之后的15位小数。是必需的,特别是因为数据的总精度只有6-7位数 - 所以在大多数 6-7“好”数字后面的'。',取决于数字的大小。

FWIW:您可以将数字转换为科学形式,然后直接按下字符串 - 这是执行以下代码的另一种方式。


  double pt[] = { 1E0,  1E1,  1E2,  1E3,  1E4,  1E5,  1E6,  1E7,  1E8,  1E9,
                  1E10, 1E11, 1E12, 1E13, 1E14, 1E15, 1E16, 1E17, 1E18, 1E19 } ;

  double xx ;
  int de ;

  de = 6 - (int)ceilf(log10f(x)) ;   /* where 'x' is the float to be shown */

  if ((de > 15) || (de < -18))       /* de > 15 -- no need to round, value too small  */
                                     /* de < 18 -- cannot round, value too big        */
    xx = x ;         /* xx is value to output */
  else
    {
      while (1)
        {
           xx = x ;

           if      (de < 0)
             xx /= pt[-de] ;
           else if (de > 0)
             xx *= pt[+de] ;

           xx = round(xx) ;

           if      (xx < pt[5])
             de += 1 ;
           else if (xx > pt[6])
             de -= 1 ;
           else
             break ;
        } ;

      if      (de < 0)
        xx *= pt[-de] ;
      else if (de > 0)
        xx /= pt[+de] ;
    } ;

  ss << std::fixed << std::setprecision(15) << xx ;