Как printf в C округляет числа с плавающей точкой? - PullRequest
3 голосов
/ 11 июня 2019

Я пытаюсь реализовать printf, и я хочу знать, как printf округляет числа с плавающей точкой, потому что я не могу найти общее правило

Если, например, ввести => printf("|%.f| |%.1f| |%.2f| |%.5f| |%.12f", 0.000099, 0.000099, 0.000099, 0.000099, 0.000099);

Вот вывод => |0| |0.0| |0.00| |0.00010| |0.000099000000

Я использую метод из IEEE-754, поэтому наше число с плавающей точкой в ​​памяти: 0.000098999999999999994037755413067714016506215557456016540527343750

У меня вопрос, когда и как мне округлить число с плавающей запятой?

Я ищу общее правило, которому я должен следовать для всех чисел с плавающей запятой.

Ответы [ 3 ]

3 голосов
/ 11 июня 2019

Не уверен, что именно так printf делает это, но, похоже, это работает для вашего примера:

Добавьте 5 / (10 ^ (количество десятичных точек + 1). Затемtruncate.

Ваша интерпретация неверна: ваш компилятор C преобразует ваши константы в удвоенные значения, поэтому он не использует 0.0000989999.... Он использует более точный двойной эквивалент.

Попробуйте это:

 printf("|%.f| |%.1f| |%.2f| |%.5f| |%.12f", (float)0.000099, (float)0.000099, (float)0.000099, (float)0.000099, (float)0.000099);

Вывод:

| 0 | | 0,0 | | 0,00 | | 0,00010 | | 0,000098999997

2 голосов
/ 11 июня 2019

Стандарт C предусматривает следующее в разделе 7.21.6.1p13:

Для e, E, f, F, g, and G преобразований, если число значащих десятичных цифр не более DECIMAL_DIG, тогда результат должен быть правильно округлен. Если число значащих десятичных цифр превышает DECIMAL_DIG, но исходное значение точно представлено с DECIMAL_DIG цифрами, то результатом должно быть точное представление с конечными нулями. В противном случае исходное значение ограничено двумя соседними десятичными строками L<U, каждая из которых имеет DECIMAL_DIG значащих цифр; значение результирующей десятичной строки D должно удовлетворять L ≤ D ≤ U с дополнительным условием, что ошибка должна иметь правильный знак для текущего направления округления.

Однако этот пункт является частью подраздела, озаглавленного «Рекомендуемая практика». (Если действует приложение F, то требуется рекомендуемая практика. См. F.5.)

«Правильно округлено» определяется текущим направлением округления. Смотри fsetround.

2 голосов
/ 11 июня 2019

Проблема, которую вы пытаетесь решить, на самом деле очень трудно решить правильно.

Многие существующие printf реализации используют код преобразования dtoa.c , написанный Дэвидом М. Гаем почти 30 лет назад.

Вы можете узнать больше об этом из этого вопроса, который не является точным дубликатом:

А эти сайты:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...