简体   繁体   English

C ++ Precision:String to Double

[英]C++ Precision: String to Double

I am having a problem with precision of a double after performing some operations on a converted string to double. 在对转换后的字符串执行某些操作后,我遇到了双精度问题。

#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;

}

This isn't the case for all numbers entered as a string, so the error isn't constant. 对于作为字符串输入的所有数字,情况并非如此,因此错误不是常数。 It only affects some numbers (34.38 seems to be constant). 它只影响一些数字(34.38似乎是不变的)。

At the minute, it returns this when i pass in a = 34.38 and i=100: 此时,当我传入a = 34.38且i = 100时,它会返回此值:

char a -- 34.38
Val ----- 34.38
modified val --- 3438
FMOD ----- 4.54747e-13

This will work if I change the Val to a float, as there is lower precision, but I need a double. 如果我将Val更改为浮点数,这将有效,因为精度较低,但我需要一个双精度数。

This also is repro when i use atof, sscanf and strtod instead of sstream. 当我使用atof,sscanf和strtod而不是sstream时,这也是repro。

In C++, what is the best way to correctly convert a string to a double, and actually return an accurate value? 在C ++中,将字符串正确转换为double的最佳方法是什么,并实际返回一个准确的值?

Thanks. 谢谢。

This is almost an exact duplicate of so many questions here - basically there is no exact representation of 34.38 in binary floating point, so your 34 + 19/50 is represented as a 34 + k/n where n is a power of two, and there is no exact power of two which has 50 as a factor, so there is no exact value of k possible. 这几乎是这里很多问题的完全重复 - 基本上没有二进制浮点的34.38的精确表示,所以你的34 + 19/50表示为34 + k / n,其中n是2的幂,并且没有两个具有50作为因子的精确幂,因此没有确切的k值可能。

If you set the output precision, you can see that the best double representation is not exact: 如果设置输出精度,则可以看到最佳双精度表示不精确:

cout << fixed << setprecision ( 20 );

gives

char a -- 34.38
val ----- 34.38000000000000255795
modified val --- 3438.00000000000045474735
FMOD ----- 0.00000000000045474735

So in answer to your question, you are already using the best way to convert a string to a double (though boost lexical cast wraps up your two or three lines into one line, so might save you writing your own function). 所以在回答你的问题时,你已经在使用最好的方法将字符串转换为double(虽然boost lexical cast将你的两行或三行包装成一行,所以可能会节省你编写自己的函数)。 The result is due to the representation used by doubles, and would apply to any finite representation based on binary floating point. 结果是由于双精度使用的表示,并且将适用于基于二进制浮点的任何有限表示。

With floats, the multiplication happens to be rounded down rather than up, so you happen to get an exact result. 对于浮点数,乘法恰好是向下舍入而不是向上,所以你碰巧得到了一个确切的结果。 This is not behaviour you can depend on. 这不是您可以依赖的行为。

The "problem" here is simply that 34.38 cannot be exactly represented in double-precision floating point. 这里的“问题”仅仅是34.38不能用双精度浮点精确表示。 You should read this article which describes why it's impossible to represent decimal values exactly in floating point. 您应该阅读本文该文章描述了为什么不可能完全以浮点表示十进制值。

If you were to examine "34.38 * 100" in hex (as per "format hex" in MATLAB for example), you'd see: 如果你用十六进制检查“34.38 * 100”(例如在MATLAB中的“格式十六进制”),你会看到:

40aadc0000000001

Notice the final digit. 注意最后的数字。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM