BFE>Как распечатать double со всей возможной точностью?
Прочитай форматы вывода для printf() где-нить в инете...
Там примерно так: %15.14lf — размер.точностьLongFloat
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
BFE>>Как распечатать double со всей возможной точностью? LVV>Прочитай форматы вывода для printf() где-нить в инете...
А где я ? Я не в интернете?
LVV>Там примерно так: %15.14lf — размер.точностьLongFloat
Примерно я и сам могу,
но ведь точность зависит от платформы/компилятора и если просто указать %15.14lf, то где гарантия, что мы не промахнулись с точностью?
просто не верно, так как выведет слишком много цифр.
Видимо надо использовать DBL_DECIMAL_DIG, но этот макрос отсутствует для C99 и C++11.
К тому же мне не понятно, надо ли использовать DBL_DECIMAL_DIG или DBL_DECIMAL_DIG + 1.
Так же не понятно, почему точность нельзя подставить прямо в printf. Зачем Digs ?
ЗЫ Если подумать, то видимо надо ещё печатать саму точность, т.е. +/- до следующего/предыдущего представимого числа...
Здравствуйте, B0FEE664, Вы писали: BFE>Как распечатать double со всей возможной точностью?
Эта задача сводится к задаче: можно ли двоичное число представить в десятичном виде. Ответ да. Но надо помнить, что каждый бит может требовать один десятичный знак для "точной" записи.
например значимость 1-ого бита 0.5. 2-ого бита 0.25 и т.д. 0.125 0.0625.
Т.е. для отображения числа нужно столько же знаков сколько бит в мантисе + в десятичном представлении целой части. Т.е. в худшем случае для числа двойной точности требудется 53 знака + ещё что-то в зависимости от формата и т.п.
BFE>просто не верно, так как выведет слишком много цифр. BFE>Видимо надо использовать DBL_DECIMAL_DIG, но этот макрос отсутствует для C99 и C++11. BFE>К тому же мне не понятно, надо ли использовать DBL_DECIMAL_DIG или DBL_DECIMAL_DIG + 1. BFE>Так же не понятно, почему точность нельзя подставить прямо в printf. Зачем Digs ?
Затем, что в формате написана звездочка.
Это чтобы можно было не константно формат задавать.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
BFE>>Так же не понятно, почему точность нельзя подставить прямо в printf. Зачем Digs ? LVV>Затем, что в формате написана звездочка. LVV>Это чтобы можно было не константно формат задавать.
BFE>DECIMAL_DIG — не int?
Кстати, gcc не ругается и так...
И работает одинаково.
Но не вижу смысла задавать константу в списке переменных.
Смысл именно в том, что меняя ПЕРЕМЕННУЮ Digs — не меняешь код printf()
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Вообще, откуда вы взяли 16, совершенно непонятно. По отношению к double, которое IEEE754 binary 64-bit portable float, есть две константы:
1. Сколько цифр десятичного текстового представления сохранится при любом значении десятичного порядка при конверсии в двоичное представление и обратно (берётся самое короткое из десятичных, которое конвертируется в то же двоичное представление), при умолчательном округлении. Это значение равно 15. Константа — DBL_DIG из <float.h>.
2. Сколько цифр десятичного представления нужно, чтобы произвольное число в двоичном виде перевести в десятичное представление и затем из него — в двоичное, чтобы значение сохранилось, при умолчательном округлении. Это число равно 17. Константа — DBL_DECIMAL_DIG из <float.h>.
Для сравнения, для single AKA float AKA IEEE754 binary 32-bit portable float — тут будет 6 и 9 (FLT_DIG, FLT_DECIMAL_DIG соответственно) — их разность на 1 больше. Для single, очень мало значений, что сохранится только 6 цифр, а не 7, но они таки есть, и это одна из причин критики формата и стандарта в целом: сделали бы significand не 23 бита, а 24 — размах порядка бы уменьшился (10^19 вместо 10^38), но точность была бы лучше формализуемой. (Я с этой критикой не согласен, но она достаточно активно звучит.)
Здравствуйте, netch80, Вы писали: N>Нет, недостаточно. Нужно 17, а не 16. Доказательство: N>
N> double f1 = 0.3;
Если копать глубже то можно заметить, что 0.3 точно даблом не задать. И изменение последнего бита даёт где-то +-6 в 17 знаке для 0.3. Это можно найти как 0.3*DBL_EPSILON(~2e-016)=~6e-17
Десятичное (17 знаков) — Двоичное (все биты)
0,30000000000000010 — 1.00110011 00110011 00110011 00110011 00110011 00110011 0101 E-10
0,30000000000000004 — 1.00110011 00110011 00110011 00110011 00110011 00110011 0100 E-10
0,29999999999999999 — 1.00110011 00110011 00110011 00110011 00110011 00110011 0011 E-10
0,29999999999999993 — 1.00110011 00110011 00110011 00110011 00110011 00110011 0010 E-10
Здравствуйте, kov_serg, Вы писали: _>соответственно "%.16g" (16 значащащих цифр) более чем достаточно.
Это правильно, но... Мы не можем в реальности все числа поместить в 16 знаков, так как первый и последний знак "делят" между собой значимость.
Практически получается, что если первые две цифры более 44, то достаточно 16 знаков, если нет, то можно добавить 17 знак, иначе мы потеряем 1 — 3 бита мантиссы.
Здравствуйте, Sergey_BG, Вы писали:
S_B>Здравствуйте, netch80, Вы писали: N>>Нет, недостаточно. Нужно 17, а не 16. Доказательство: N>>
N> double f1 = 0.3;
S_B>Если копать глубже то можно заметить, что 0.3 точно даблом не задать.
Да. Но это тут и не ставилось целью. Я взял самый знаменитый пример, где два числа отличаются ровно 1 младшим битом мантиссы, то есть минимально возможным изменением в двоичном представлении. Цель была именно в этой минимальности.
S_B> И изменение последнего бита даёт где-то +-6 в 17 знаке для 0.3. Это можно найти как 0.3*DBL_EPSILON(~2e-016)=~6e-17 S_B>Десятичное (17 знаков) — Двоичное (все биты) S_B>0,30000000000000010 — 1.00110011 00110011 00110011 00110011 00110011 00110011 0101 E-10 S_B>0,30000000000000004 — 1.00110011 00110011 00110011 00110011 00110011 00110011 0100 E-10 S_B>0,29999999999999999 — 1.00110011 00110011 00110011 00110011 00110011 00110011 0011 E-10 S_B>0,29999999999999993 — 1.00110011 00110011 00110011 00110011 00110011 00110011 0010 E-10
Имеет смысл показать это также на примере расширенного выхлопа той же тестовой программы: добавляю %a и %.54g:
Здравствуйте, B0FEE664, Вы писали:
BFE>но ведь точность зависит от платформы/компилятора и если просто указать %15.14lf, то где гарантия, что мы не промахнулись с точностью?
Ну в общем-то, уже не зависит. Сейчас везде IEEE 754
Здравствуйте, LaptevVV, Вы писали:
BFE>>Как распечатать double со всей возможной точностью? LVV>Прочитай форматы вывода для printf() где-нить в инете... LVV>Там примерно так: %15.14lf — размер.точностьLongFloat
Было бы еще неплохо эту самую точность с реальной точностью внутреннего представления соотнести. А то библиотеке-то не жалко дополнительных циферок в конце понапечатать, но не факт, что они будут что-либо значить...
Здравствуйте, B0FEE664, Вы писали:
BFE>Как распечатать double со всей возможной точностью?
Если под всей возможной точностью понимается, что потом считанное из вывода число будет внутри те же биты иметь (round trip conversion) и в то же время выводится минимально возможное количество децимальных циферок, то семейство printf — не самый удачный выбор. Надо взять или fmtlib или to_chars из <charconv>. Последний, по крайней мере от микрософт, как хвалятся, это умеет.