2012-07-27 428 views
7

在Java中處理浮點值時,調用toString()方法會給出一個具有正確浮點有效數字的打印值。但是,在C++中,通過stringstream打印浮點數將在5位或更少位數後四捨五入。有沒有辦法將C++中的float漂亮地打印到(假定的)有效數字的正確數目上?如何計算C++ double的重要小數位數?


編輯:我想我被誤解了。我希望輸出具有動態長度,而不是固定的精度。我熟悉setprecision。如果您查看Double的Java源代碼,它會以某種方式計算有效數字的數量,我真的很想了解它是如何工作的和/或在C++中如何輕鬆地複製它。

/* 
* FIRST IMPORTANT CONSTRUCTOR: DOUBLE 
*/ 
public FloatingDecimal(double d) 
{ 
    long dBits = Double.doubleToLongBits(d); 
    long fractBits; 
    int  binExp; 
    int  nSignificantBits; 

    // discover and delete sign 
    if ((dBits&signMask) != 0){ 
     isNegative = true; 
     dBits ^= signMask; 
    } else { 
     isNegative = false; 
    } 
    // Begin to unpack 
    // Discover obvious special cases of NaN and Infinity. 
    binExp = (int)((dBits&expMask) >> expShift); 
    fractBits = dBits&fractMask; 
    if (binExp == (int)(expMask>>expShift)) { 
     isExceptional = true; 
     if (fractBits == 0L){ 
      digits = infinity; 
     } else { 
      digits = notANumber; 
      isNegative = false; // NaN has no sign! 
     } 
     nDigits = digits.length; 
     return; 
    } 
    isExceptional = false; 
    // Finish unpacking 
    // Normalize denormalized numbers. 
    // Insert assumed high-order bit for normalized numbers. 
    // Subtract exponent bias. 
    if (binExp == 0){ 
     if (fractBits == 0L){ 
      // not a denorm, just a 0! 
      decExponent = 0; 
      digits = zero; 
      nDigits = 1; 
      return; 
     } 
     while ((fractBits&fractHOB) == 0L){ 
      fractBits <<= 1; 
      binExp -= 1; 
     } 
     nSignificantBits = expShift + binExp +1; // recall binExp is - shift count. 
     binExp += 1; 
    } else { 
     fractBits |= fractHOB; 
     nSignificantBits = expShift+1; 
    } 
    binExp -= expBias; 
    // call the routine that actually does all the hard work. 
    dtoa(binExp, fractBits, nSignificantBits); 
} 

此功能後,它會調用dtoa(binExp, fractBits, nSignificantBits);它處理了一堆的情況下 - 這是來自OpenJDK6


爲了更清楚,一個例子: 的Java:

double test1 = 1.2593; 
double test2 = 0.004963; 
double test3 = 1.55558742563; 

System.out.println(test1); 
System.out.println(test2); 
System.out.println(test3); 

輸出:

1.2593 
0.004963 
1.55558742563 

C++:

std::cout << test1 << "\n"; 
std::cout << test2 << "\n"; 
std::cout << test3 << "\n"; 

輸出:

1.2593 
0.004963 
1.55559 
+3

的'toString'方法並沒有給出「正確的數字」有效數字;它無法知道哪些數字是重要的。 IEEE浮點數不代表那些信息。 – 2012-07-27 20:41:14

+0

僅供參考,以下是[*自定義格式*](http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html)的常用Java方法。 – trashgod 2012-07-27 20:44:15

+0

Java在打印時對double值做了一系列的計算 - 我只是不夠了解它在做什麼。見編輯 – dave 2012-07-27 21:26:56

回答

5

我認爲你是在談論如何打印的浮點數字,讓您閱讀完全相同的浮點數後面的最小數量。本文是對這個棘手問題的一個很好的介紹。

http://grouper.ieee.org/groups/754/email/pdfq3pavhBfih.pdf

的DTOA功能看起來像大衛·蓋伊的工作,你可以在這裏找到源http://www.netlib.org/fp/dtoa.c(雖然這是C不是Java)。

蓋伊還寫了一篇關於他的方法的論文。我沒有鏈接,但它在上面的文章中提到,所以你可以谷歌它。

+0

謝謝!我覺得你是唯一獲得我所說的話的人。 – dave 2012-07-27 23:13:04

0

可以使用的ios_base ::精度的技術,您可以在指定的位數您想要

例如

#include <iostream> 
using namespace std; 

int main() { 
double f = 3.14159; 
cout.unsetf(ios::floatfield);   // floatfield not set 
cout.precision(5); 
cout << f << endl; 
cout.precision(10); 
cout << f << endl; 
cout.setf(ios::fixed,ios::floatfield); // floatfield set to fixed 
cout << f << endl; 
return 0; 

上面的代碼與輸出
3.1416
3.14159
3.1415900000

+0

我試圖避免的是你的例子中的尾隨零。我不想爲我的輸出固定值。 – dave 2012-07-27 21:31:02

0

有一個工具,叫做numeric_limits:

#include <limits> 

    ... 
    int num10 = std::numeric_limits<double>::digits10; 
    int max_num10 = std::numeric_limits<double>::max_digits10; 

注意,IEEE的數字並不精確表示bydecimal數字。這些是二進制數量。更準確的數字是二進制的比特數:

int bits = std::numeric_limits<double>::digits; 

要漂亮打印所有顯著位使用setprecision本:

out.setprecision(std::numeric_limits<double>::digits10); 
+0

這不是我要找的 – dave 2012-07-27 23:12:13

+0

好吧,我明白了。你想要通過數字操作跟蹤施工精度的數字嗎? C++標準沒有這個。努力添加多精度數字。我認爲你的要求對這些數字是合理的。基本上,基本的浮點數就是沒有這個智慧,永遠不會。 – emsr 2012-07-28 03:46:19

+0

看看這個:http://www.holoborodko.com/pavel/mpfr/。我認爲這是你想要的。祝你好運。 – emsr 2012-07-28 03:49:45