Я рекомендую @Jens Gustedt шістнадцятковий розчин: використовуйте% a.
ОП хоче «друкувати з максимальною точністю (або принаймні до найбільш значущої десяткової)».
Простим прикладом може бути друк однієї сьомої як у:
#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01
Але давайте копаємо глибше ...
Математично відповідь - "0,142857 142857 142857 ...", але ми використовуємо кінцеві точні числа з плаваючою комою. Припустимо, двійкові IEEE 754 з подвійною точністю . Тож OneSeventh = 1.0/7.0
результати в наведеному нижче значенні. Також показані попередні та наступні представницькі double
номери з плаваючою комою.
OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after = 0.1428571428571428 769682682968777953647077083587646484375
Друк точного десяткового подання double
обмеженого використання.
У C є 2 родини макросів, <float.h>
щоб допомогти нам.
Перший набір - це кількість значущих цифр для друку в рядку десятковими, тому при скануванні рядка назад ми отримуємо оригінальну плаваючу крапку. Тут показано мінімальне значення специфікації C та компілятор вибірки С11.
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)
Другий набір - це кількість значущих цифр, рядки можуть бути скановані в плаваючу крапку, а потім надрукується FP, зберігаючи таку ж презентацію рядків. Тут показано мінімальне значення специфікації C та компілятор вибірки С11. Я вважаю, що доступний до C99.
FLT_DIG 6, 6 (float)
DBL_DIG 10, 15 (double)
LDBL_DIG 10, 18 (long double)
Перший набір макросів, схоже, відповідає цілі ОП - значущих цифр. Але цей макрос доступний не завжди.
#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" - це суть моєї попередньої відповіді. Його центр зосереджений на тому, що якщо ви знаєте зворотну конверсію string-FP-рядок (встановлено №2 макросів C89), як можна визначити цифри для FP-string-FP (встановити №1 макросів, доступних після C89)? Загалом, результат додав 3.
Тепер, скільки значущих цифр для друку відомо, і проходять через <float.h>
.
Для друку N значущих десяткових цифр можна використовувати різні формати.
З "%e"
, поле точності - це кількість цифр після первинної цифри і десяткової крапки. Так - 1
і в порядку. Примітка. Це -1
не в початковійint Digs = DECIMAL_DIG;
printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01
З "%f"
, поле точності - це кількість цифр після десяткової крапки. Для такої кількості, як OneSeventh/1000000.0
треба, потрібно було б OP_DBL_Digs + 6
побачити всі суттєві цифри.
printf("%.*f\n", OP_DBL_Digs , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285
Примітка. Багато хто звик "%f"
. На екрані відображається 6 цифр після коми; 6 - значення за замовчуванням на дисплеї, а не точність числа.