2014-10-29 52 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