2014-10-29 33 views
0

我正在寻找函数来可靠地将字符串转换为双精度,然后返回到C++中的字符串,以便输出字符串与输入字符串完全相同。但即使经过数小时的搜索和尝试,我也找不到可靠的功能。可靠转换字符串双打和返回

要检查功能是可靠的我做了如下试验:

#include <iostream> 
#include <string> 

using namespace std; 

string double2string(double value){ 
    //... 
} 
double string2double(string value){ 
    //... 
} 


int main(){ 

    string strings[] = { 
     "111111111111110000", 
     "11111111111111000", 
     "1111111111111100", 
     "111111111111110", 
     "11111111111111", 
     "1111111111111.1", 
     "111111111111.11", 
     "11111111111.111", 
     "1111111111.1111", 
     "111111111.11111", 
     "11111111.111111", 
     "1111111.1111111", 
     "111111.11111111", 
     "11111.111111111", 
     "1111.1111111111", 
     "111.11111111111", 
     "11.111111111111", 
     "1.1111111111111", 
     "0.11111111111111", 
     "0.011111111111111", 
     "0.0011111111111111", 
     "0.00011111111111111" 
    }; 
    double doubles[] = { 
     111111111111110000, 
     11111111111111000, 
     1111111111111100, 
     111111111111110, 
     11111111111111, 
     1111111111111.1, 
     111111111111.11, 
     11111111111.111, 
     1111111111.1111, 
     111111111.11111, 
     11111111.111111, 
     1111111.1111111, 
     111111.11111111, 
     11111.111111111, 
     1111.1111111111, 
     111.11111111111, 
     11.111111111111, 
     1.1111111111111, 
     0.11111111111111, 
     0.011111111111111, 
     0.0011111111111111, 
     0.00011111111111111 
    }; 

    for(int i = 0; i < 22; i++){ 
     cout 
      << (string2double(strings[i])==doubles[i]) 
      << " " 
      << (double2string(doubles[i])==strings[i]) 
      << endl; 
    } 



    return 0; 
} 

“?为什么这个测试”,你可能会问。让我解释一下: C++ double有52位来保存一个整数。这个数字最高可以是2^52-1,或者4503599627370495。这个数字是16位数字。但由于并非所有16位数字的数字都适合那些没有溢出的位,我的要求是只可靠地转换所有15位数字的数字。前导或尾随零不计数,因为它们可用11个指数位表示。

所以,基本上,我确保所有这些数字在理论上都适合双倍,没有任何溢出,以便我可以将它们1:1转换回字符串。

现在:您是否知道任何函数可以从double转换为string并返回,只需打印出“1”即可完成测试?

+2

您的测试基于有缺陷的假设,例如,“X.1”可以首先表示为double(它不能)。如果*用double开始*,将其转换为字符串,打印字符串,然后转换为double,则会发现它按照您的预期进行往返。但并不是每个数字实际上都可以表现为一个双。基本上,无论你有多精确,都有一些数字不能用基2指数表示法表示,这就是浮点数的编码方式。 – aruisdante 2014-10-29 13:56:57

+4

他们不“理论上适合双倍”。没有一个小数值可以用二进制浮点格式精确表示。如果您需要准确表示非整数小数,则需要使用不同的表示法。 – 2014-10-29 13:57:12

+0

@tgmath带来了非常好的一点。除非你指定为双字面值,否则通过'=='比较任意两个双精度的几率是天文数字低的,这要归功于前面提到的双精度内在的数字不稳定性。这就是为什么,例如'for(double i = 0.0; i!= 1.0; i + = 0.1)'将永远不会终止。 – aruisdante 2014-10-29 14:01:39

回答

1

这基本上是不可能的。指定 文本格式的方法太多,关于此格式的信息在您转换为double时丢失了 。在我的机器,例如, 以下所有字符串转换为相同的双:

1 
1.0 
1e0 
1.000000000000000000001 
+1.0 
0001.0 

等等。一旦你拥有两倍的这个信息,你的信息就会丢失。

如果您将输入限制为特定格式,比如说科学总数为15位的科学 ,那么如果您的机器使用IEEE,则​​最多15位数字 的任何数据都应该正确往返。

+0

我只对outwrite表示感兴趣。它不能读取'1e0',但如果它能够这样做,它应该被转换回'1'。基本上我想要最紧凑的版本,不使用'e',这意味着如果不需要它们,就可以去掉前导零和尾随零。 – 2014-10-29 15:05:01

+0

是的,那么['std :: stringstream'](http://www.cplusplus.com/reference/sstream/stringstream/)可能就是你正在寻找的东西。您可以将ss转换为字符串,然后再将ss转换成double。您可以调整行为,但默认值为十进制表示法,不带前导/尾随零(除了-1.0 aruisdante 2014-10-29 15:11:38

+0

@arusidante在使用stringstream转换为字符串时,它只会在逗号后长达6位数。因此,0.1111111将被转换为“0.111111”,缺少一个逗号。此外,它还为数字添加了不需要的e + xxx语法。任何workaraund? – 2014-10-29 15:52:33