2012-07-27 14 views
7

Podczas przetwarzania wartości zmiennoprzecinkowych w Javie, wywołanie metody toString() daje wydrukowaną wartość, która ma prawidłową liczbę znaczących liczb zmiennoprzecinkowych. Jednak w C++, drukowanie float za pośrednictwem stringstream będzie zaokrąglało wartość po 5 lub mniej cyfrach. Czy istnieje sposób na "ładny wydruk" float w C++ do (zakładanej) poprawnej liczby znaczących liczb?Jak obliczyć liczbę znaczących cyfr dziesiętnych C++ double?


EDYCJA: Myślę, że jestem źle rozumiany. Chcę, aby wyjście miało dynamiczną długość, a nie stałą precyzję. Jestem zaznajomiony z setprecision. Jeśli spojrzysz na źródło java dla Double, to w jakiś sposób oblicza ono liczbę cyfr znaczących i naprawdę chciałbym zrozumieć, jak to działa i/lub jak łatwo jest to replikować w 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); 
} 

Po tej funkcji, wywołuje dtoa(binExp, fractBits, nSignificantBits); który obsługuje kilka przypadków - to z OpenJDK6


Dla większej jasności, przykład: 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); 

Output :

1.2593 
0.004963 
1.55558742563 

C++:

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

wyjściowa:

1.2593 
0.004963 
1.55559 
+3

Opcja 'metoda toString' nie daje„prawidłowy numer”z znaczące liczby; nie ma możliwości sprawdzenia, które z danych są znaczące. Liczby zmiennoprzecinkowe IEEE nie reprezentują tych informacji. –

+0

Dla odniesienia, tutaj jest wspólne podejście Java do [* Customizing Formats *] (http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html). – trashgod

+0

Java robi serię obliczeń na podwójnej wartości podczas drukowania - ja po prostu nie mam wystarczającej wiedzy, aby zrozumieć, co robi. Zobacz redakcję – dave

Odpowiedz

5

myślę mówisz jak wydrukować minimalną liczbę cyfr pływających punktowych, które pozwalają odczytać dokładnie taką samą liczbę zmiennoprzecinkową powrotem. Ten artykuł jest dobrym wprowadzeniem do tego trudnego problemu.

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

Funkcja dtoa wygląda praca Davida gay, można znaleźć źródło tutaj http://www.netlib.org/fp/dtoa.c (choć nie jest to C Java).

Gay napisał także artykuł o swojej metodzie. Nie mam linku, ale jest on wymieniony w powyższym artykule, więc prawdopodobnie możesz google.

+0

Dzięki! Czuję się, jakbyś był jedyną osobą, która dostała to, o czym mówiłem. – dave

0

Można użyć techniki ios_base :: precyzję w którym można określić liczbę cyfr chcesz

Na przykład

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

Powyższy kod z wyjściem
3,1416
3,14159
3,1415900000

+0

To, czego próbuję uniknąć, to końcowe zera w twoim przykładzie. Nie chcę stałej wartości dla moich wyników. – dave

0

istnieje narzędzie o nazwie numeric_limits:

#include <limits> 

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

Należy pamiętać, że numery nie są reprezentowane IEEE dokładnie bydecimal cyfr. Są to ilości binarne.Bardziej dokładna liczba jest liczbą bitów binarnych:

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

ładnego wydrukować wszystkie cyfry znaczące używać setprecision z tym:

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

to nie jest to, czego szukam – dave

+0

OK, rozumiem, myślę. Potrzebujesz liczb, które śledzą precyzję od budowy poprzez operacje numeryczne? Standard C++ tego nie ma. Podejmowane są wysiłki, aby dodać liczby o dużej precyzji. Myślę, że twój wymóg jest uzasadniony dla takich liczb. Zasadniczo, podstawowe liczby zmiennoprzecinkowe po prostu nie mają sprytów i nigdy tego nie zrobią. – emsr

+0

Sprawdź to: http://www.holoborodko.com/pavel/mpfr/. Myślę, że tego właśnie chcesz. Powodzenia. – emsr

Powiązane problemy