Я все время натыкаюсь на спецификаторы формата для семейства функций printf (). Я хочу иметь возможность печатать двойное (или плавающее) число с максимальным заданным количеством цифр после десятичной точки. Если я использую:
printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);
я получил
359.013
359.010
Вместо желаемого
359.013
359.01
Кто-нибудь может мне помочь?
Ответы:
Это невозможно сделать с помощью
printf
спецификаторов обычного формата. Самое близкое, что вы могли бы получить:но ".6" - это общая числовая ширина, поэтому
ломает это.
Что вы можете сделать, так это ввести
sprintf("%.20g")
число в строковый буфер, а затем манипулировать строкой, чтобы после десятичной точки было только N символов.Предполагая, что ваше число находится в переменной num, следующая функция удалит все, кроме первых
N
десятичных знаков, затем удалит конечные нули (и десятичную точку, если все они были нулями).Если вас не устраивает аспект усечения (который превратился бы
0.12399
в его,0.123
а не в округление0.124
), вы действительно можете использовать средства округления, уже предоставленныеprintf
. Вам просто нужно предварительно проанализировать число, чтобы динамически создать ширину, а затем использовать их, чтобы превратить число в строку:Весь смысл
nDecimals()
в этом случае состоит в том, чтобы правильно определить ширину полей, а затем отформатировать число, используя строку формата на основе этого. Тестовый комплектmain()
демонстрирует это в действии:Как только у вас будет правильно округленное значение, вы можете еще раз передать его,
morphNumericString()
чтобы удалить конечные нули, просто изменив:в:
(или вызов
morphNumericString
в конце,nDecimals
но в этом случае я бы, вероятно, просто объединил их в одну функцию), и вы получите:источник
.
в некоторых странах десятичный разряд - это фактически,
запятая.atof
вернет то же значение.0.10000000000000000555
будет0.1
при удалении. Проблема может прийти , если вы немного иметь значение при таких , как будто ближе представлении42.1
было42.099999999314159
. Если вы действительно хотите справиться с этим, вам, вероятно, придется округлить на основе удаленной последней цифры, а не усекать.printf
-подобных функций, поскольку они уже поддерживают динамические параметры (*
специальный символ): например,printf("%*.*f", total, decimals, x);
выводит число с динамически заданной общей длиной поля и десятичными знаками.Чтобы избавиться от нулей в конце, используйте формат "% g":
После того, как вопрос был немного прояснен, требовалось не только подавление нулей, но и ограничение вывода тремя десятичными знаками. Я думаю, что это невозможно сделать только с помощью строк формата sprintf. Как указал Пакс Диабло , потребуется манипулирование строками.
источник
Мне нравится ответ Р., слегка измененный:
«1000» определяет точность.
Степень округления до 0,5.
РЕДАКТИРОВАТЬ
Хорошо, этот ответ редактировался несколько раз, и я потерял все, о чем думал несколько лет назад (и изначально он не отвечал всем критериям). Итак, вот новая версия (которая соответствует всем критериям и правильно обрабатывает отрицательные числа):
И тестовые случаи:
И вывод тестов:
Теперь все критерии соблюдены:
К сожалению, этот ответ состоит из двух
sprintf
строк и не возвращает строку.источник
Я ищу в строке (начиная с крайнего правого) первый символ в диапазоне
1
до9
(значение ASCII49
-57
), затемnull
(устанавливаю0
) каждый символ справа от него - см. Ниже:источник
Как насчет чего-то вроде этого (могут быть ошибки округления и проблемы с отрицательными значениями, которые требуют отладки, оставленные в качестве упражнения для читателя):
Это немного программно, но, по крайней мере, не заставляет вас манипулировать строками.
источник
Простое решение, но оно выполняет свою работу, назначает известную длину и точность и исключает вероятность перехода в экспоненциальный формат (что является риском при использовании% g):
Добавьте или удалите «elses», если вы хотите максимум 2 десятичных знака; 4 десятичных знака; и т.п.
Например, если вам нужно 2 десятичных знака:
Если вы хотите указать минимальную ширину, чтобы поля оставались выровненными, при необходимости увеличивайте ее, например:
Вы также можете преобразовать это в функцию, в которой вы передаете желаемую ширину поля:
источник
d = 0.0001
: тогдаfloor(d)
есть0
, поэтому разница больше 0,000001, поэтомуDoubleEquals
ложь, поэтому спецификатор не будет использоваться"%.0f"
: вы увидите конечные нули от"%*.2f"
или"%*.3f"
. Так что это не отвечает на вопрос.Я обнаружил проблемы в некоторых из опубликованных решений. Я собрал это на основе ответов выше. Мне кажется, это работает.
источник
Некоторые из высоко оцененных решений предполагают
%g
спецификатор преобразованияprintf
. Это неверно, потому что есть случаи, когда%g
будут получены научные обозначения. Другие решения используют математику для вывода желаемого количества десятичных цифр.Я думаю , что самое простое решение состоит в использовании
sprintf
с%f
спецификатором преобразования и вручную удалить конечные нули и , возможно , десятичную точку из результата. Вот решение C99:Обратите внимание, что символы, используемые для цифр и десятичного разделителя, зависят от текущего языкового стандарта. Приведенный выше код предполагает языковой стандарт C или английский (США).
источник
Вот моя первая попытка ответить:
Известные ошибки: Возможное переполнение буфера в зависимости от формата. Если "." присутствует по причине, отличной от% f, возможен неправильный результат.
источник
Почему бы просто не сделать это?
источник
Небольшие отклонения от приведенного выше:
Код здесь:
Он все еще может переполниться, поэтому будьте осторожны; P
источник
Я бы сказал, вам следует использовать
printf("%.8g",value);
Если вы используете,
"%.6g"
вы не получите желаемого результата для некоторых чисел, например 32.230210, он должен печатать,32.23021
но он печатает32.2302
источник
Ваш код округляется до трех десятичных знаков из-за ".3" перед f
Таким образом, если вы округлили вторую строку до двух десятичных знаков, вы должны изменить ее на следующее:
Этот код выдаст желаемый результат:
* Обратите внимание, это предполагает, что у вас уже есть печать на отдельных строках, в противном случае следующее предотвратит печать на той же строке:
Следующий исходный код программы был моим тестом для этого ответа.
источник