C++ Precision:String to Double

don*_*lmg 4 c++ floating-point floating-accuracy

在对转换后的字符串执行某些操作后,我遇到了双精度问题.

#include <iostream>   
#include <sstream>
#include <math.h>

using namespace std;

// conversion function
void convert(const char * a, const int i, double &out)
{

   double val;

   istringstream in(a);
   in >> val;

   cout << "char a -- " << a << endl;
   cout << "val ----- " << val << endl;

   val *= i;

   cout << "modified val --- " << val << endl;
   cout << "FMOD ----- " << fmod(val, 1) << endl;

   out = val;

   return 0;

}
Run Code Online (Sandbox Code Playgroud)

对于作为字符串输入的所有数字,情况并非如此,因此错误不是常数.它只影响一些数字(34.38似乎是不变的).

此时,当我传入a = 34.38且i = 100时,它会返回此值:

char a -- 34.38
Val ----- 34.38
modified val --- 3438
FMOD ----- 4.54747e-13
Run Code Online (Sandbox Code Playgroud)

如果我将Val更改为浮点数,这将有效,因为精度较低,但我需要一个双精度数.

当我使用atof,sscanf和strtod而不是sstream时,这也是repro.

在C++中,将字符串正确转换为double的最佳方法是什么,并实际返回一个准确的值?

谢谢.

Pet*_*ham 11

这几乎是这里很多问题的完全重复 - 基本上没有二进制浮点的34.38的精确表示,所以你的34 + 19/50表示为34 + k/n,其中n是2的幂,并且没有两个具有50作为因子的精确幂,因此没有确切的k值可能.

如果设置输出精度,则可以看到最佳双精度表示不精确:

cout << fixed << setprecision ( 20 );
Run Code Online (Sandbox Code Playgroud)

char a -- 34.38
val ----- 34.38000000000000255795
modified val --- 3438.00000000000045474735
FMOD ----- 0.00000000000045474735
Run Code Online (Sandbox Code Playgroud)

所以在回答你的问题时,你已经在使用最好的方法将字符串转换为double(虽然boost lexical cast将你的两行或三行包装成一行,所以可能会节省你编写自己的函数).结果是由于双精度使用的表示,并且将适用于基于二进制浮点的任何有限表示.

对于浮点数,乘法恰好是向下舍入而不是向上,所以你碰巧得到了一个确切的结果.这不是您可以依赖的行为.