我發現這是在我進行字符串到雙精度轉換練習(例如stdlib.h中的atof)時發生的。我想把一串「625」(表示雙倍數的一部分)放到一個雙倍變量0.625。奇怪的是,當我把它作爲我的練習的一部分時,它導致0.62500000000000011或類似的結果不準確。然而,當我把它放在一個獨立的方式,它工作得很好,如下面的代碼:C++中的double類型可變乘法導致值不準確
int main(int argc, char **argv) {
string str = "625";
double mask = 0.1;
double frac = 0.0;
for(int i = 0; i < static_cast<int>(str.length()); ++i) {
frac += (str[i] - '0')*mask;
mask *= 0.1;
}
cout << frac << endl;
}
上面的代碼給出準確的結果(0.625)。但是,下面的代碼給出不準確的結果(0.62500000000000011):
string PrintDecimal(string input) {
long int_part = 0;
double frac_part = 0.0;
bool is_positive;
size_t found;
string ret_str;
found = input.find('-');
if(found == string::npos) {
is_positive = true;
}
else {
is_positive = false;
input.erase(found, 1);
}
found = input.find('.');
if(found == string::npos) {
int mask = 1;
char app_char;
for(int i = static_cast<int>(input.length()-1); i > -1; --i) {
int_part += (input[i] - '0')*mask;
mask *= 10;
}
while(int_part != 0) {
app_char = (int_part % 2 == 0) ? '0' : '1';
ret_str.push_back(app_char);
int_part /= 2;
}
if(is_positive == false) {
ret_str.append("-");
}
reverse(ret_str.begin(), ret_str.end());
}
else {
char app_char;
long mask_int = 1;
double mask_frac = 0.1;
string int_part_str = input.substr(0, found);
//string frac_part_str = input.substr(found+1, input.length()-found-1);
string frac_part_str = "0.";
frac_part_str.append(input.substr(found+1, input.length()-found-1));
for(int i = static_cast<int>(int_part_str.length()-1); i > -1; --i) {
int_part += (int_part_str[i] - '0')*mask_int;
mask_int *= 10;
}
//This converting causes 6*0.1 = 0.6000000000009
/*
for(int i = 0; i < static_cast<int>(frac_part_str.length()); ++i) {
frac_part += (frac_part_str[i] - '0')*mask_frac;
mask_frac *= 0.1;
}
*/
frac_part = atof(frac_part_str.c_str()); //This works well.
while(int_part != 0) {
app_char = (int_part % 2 == 0) ? '0' : '1';
ret_str.push_back(app_char);
int_part /= 2;
}
if(is_positive == false) {
ret_str.append("-");
}
reverse(ret_str.begin(), ret_str.end());
ret_str.push_back('.');
found = ret_str.find('.');
while(frac_part != 0.0) {
if(ret_str.length() - found > 64) {
cerr << "Can't express accurately." << endl;
return "Error";
}
frac_part *= 2;
if(frac_part >= 1.0) {
ret_str.push_back('1');
frac_part -= 1;
}
else {
ret_str.push_back('0');
}
}
}
cout << ret_str << endl;
return ret_str;
}
我使用的編譯器的版本是gcc版本4.2.1(蘋果公司建立5666)(點3)。 請注意代碼中引起問題的註釋部分。我請求你的想法來解決這個問題。謝謝!
歡迎來到浮點的美妙世界。 – 2012-01-07 15:08:00
對我來說看起來相當準確。它只有0.00000000000000011出來! – 2012-01-07 15:16:05
我認爲幾乎每個人都被這個浮點數引向一次。如果我告訴你寫1/3沒有分數,你會寫0.3333 ...在某些時候,你需要停下來說(足夠了)。現在,作爲一個練習,做同樣的1/10(0.1),但在二進制。 – 2012-01-07 15:29:20