Polecam rozwiązanie szesnastkowe @Jens Gustedt: użyj% a.
OP chce „drukować z maksymalną precyzją (lub przynajmniej do najbardziej znaczącego miejsca po przecinku)”.
Prostym przykładem byłoby wydrukowanie jednej siódmej, jak w:
#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01
Ale poszukajmy głębiej ...
Matematycznie odpowiedź brzmi „0,142857 142857 142857 ...”, ale używamy liczb zmiennoprzecinkowych o skończonej precyzji. Załóżmy, że plik binarny o podwójnej precyzji IEEE 754 . Więc OneSeventh = 1.0/7.0
wyniki w wartości poniżej. Pokazane są również poprzedzające i następujące reprezentowalne double
liczby zmiennoprzecinkowe.
OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after = 0.1428571428571428 769682682968777953647077083587646484375
Drukowanie dokładnej reprezentacji dziesiętnej a double
ma ograniczone zastosowania.
C ma 2 rodziny makr, <float.h>
które nam pomagają.
Pierwszy zestaw to liczba cyfr znaczących do wydrukowania w ciągu w postaci dziesiętnej, więc podczas skanowania łańcucha z powrotem otrzymujemy pierwotny zmiennoprzecinkowy. Są tam pokazane z minimalną wartością specyfikacji C i przykładowym kompilatorem C11.
FLT_DECIMAL_DIG 6, 9 (float) (C11)
DBL_DECIMAL_DIG 10, 17 (double) (C11)
LDBL_DECIMAL_DIG 10, 21 (long double) (C11)
DECIMAL_DIG 10, 21 (widest supported floating type) (C99)
Drugi zestaw to liczba cyfr znaczących, które łańcuch może być zeskanowany do postaci zmiennoprzecinkowej, a następnie wydrukowany FP, nadal zachowując tę samą prezentację ciągu. Są tam pokazane z minimalną wartością specyfikacji C i przykładowym kompilatorem C11. Uważam, że dostępne przed C99.
FLT_DIG 6, 6 (float)
DBL_DIG 10, 15 (double)
LDBL_DIG 10, 18 (long double)
Wydaje się, że pierwszy zestaw makr spełnia cel OP dotyczący znaczących cyfr. Ale to makro nie zawsze jest dostępne.
#ifdef DBL_DECIMAL_DIG
#define OP_DBL_Digs (DBL_DECIMAL_DIG)
#else
#ifdef DECIMAL_DIG
#define OP_DBL_Digs (DECIMAL_DIG)
#else
#define OP_DBL_Digs (DBL_DIG + 3)
#endif
#endif
„+ 3” było sednem mojej poprzedniej odpowiedzi. Skupia się na tym, że znając ciąg konwersji w obie strony łańcuch-ciąg FP (zestaw nr 2 dostępnych makr C89), w jaki sposób można określić cyfry dla ciągu FP-FP (zestaw makr zestaw nr 1 dostępny po C89)? Ogólnie rzecz biorąc, wynikiem było dodanie 3.
Teraz, ile znaczących cyfr do wydrukowania jest znanych i używanych <float.h>
.
Aby wydrukować N znaczących cyfr dziesiętnych, można użyć różnych formatów.
W "%e"
przypadku pola dokładności jest liczba cyfr po cyfrze wiodącej i kropce dziesiętnej. Tak - 1
jest w porządku. Uwaga: -1
to nie jest na początkuint Digs = DECIMAL_DIG;
printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01
W "%f"
przypadku polem dokładności jest liczba cyfr po przecinku. W przypadku liczby takiej jak OneSeventh/1000000.0
, należałoby OP_DBL_Digs + 6
zobaczyć wszystkie znaczące cyfry.
printf("%.*f\n", OP_DBL_Digs , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285
Uwaga: wielu jest przyzwyczajonych do "%f"
. To wyświetla 6 cyfr po przecinku; 6 jest domyślnym wyświetlaniem, a nie dokładnością liczby.