Используйте sprintf для форматирования поплавков без десятичных знаков, если целое число

Первоначально я использовал sprintf с поплавками всегда с 2 десятичными знаками, используя следующий код:

static void MyFunc(char* buffer, const float percentage) { sprintf(buffer, "%.2f", percentage); } 

Одно из процентных значений прошло 0x419FFFFF 20 (отладчик), это напечатало 20,00 в буфер.

Вместо этого я хотел бы показать 2 десятичных разряда, если не целое число, например

 94.74 displayed as 94.74 94.7 displayed as 94.70 0 displayed as 0 5 displayed as 5 100 displayed as 100 

В настоящее время я использую следующий код:

 static void MyFunc(char* buffer, const float percentage) { int fractional_part = ((percentage - (int)percentage) * 100); if (0 == fractional_part) { sprintf(buffer, "%d", (int)percentage); } else { sprintf(buffer, "%.2f", percentage); } } 

Теперь, если передано 0x419FFFFF 20 (представление отладчика), дробная часть вычисляется как 99. Я предполагаю, что тогда сумма для fractional_part заканчивается (19.99 – 19) * 100 = 99. Почему тогда первый пример не печатает 19.99 в буфер?

Какое правильное решение для моей проблемы?

Ваша проблема аппроксимации.

Предположим, что процент составляет 19,999. Тогда fractional_part будет равен 99, а ветвь с плавающей запятой будет вызвана.

Но печать 19.999 с двумя десятичными знаками обойдется до 20.00, и это то, что напечатано.

Вы всегда можете использовать ветвь с плавающей запятой, чтобы получить согласованные результаты, а затем усечь на. если он выходит с ‘.00’. В противном случае вы рискуете своим испытанием и внутренними printf некоторое время.

 #include  #include  int main(int argc, char **argv) { float percentage = 19.999; char buffer[50]; for (percentage = 19.990; percentage < 20.001; percentage += 0.001) { sprintf(buffer, "%.2f", percentage); char *p = strstr(buffer, ".00"); if (p) *p = 0x0; printf("%.3f rendered as %.2f and becomes %s\n", percentage, percentage, buffer); } return 0; } 19.990 rendered as 19.99 and becomes 19.99 19.991 rendered as 19.99 and becomes 19.99 19.992 rendered as 19.99 and becomes 19.99 19.993 rendered as 19.99 and becomes 19.99 19.994 rendered as 19.99 and becomes 19.99 19.995 rendered as 19.99 and becomes 19.99 19.996 rendered as 20.00 and becomes 20 19.997 rendered as 20.00 and becomes 20 19.998 rendered as 20.00 and becomes 20 19.999 rendered as 20.00 and becomes 20 20.000 rendered as 20.00 and becomes 20 20.001 rendered as 20.00 and becomes 20 

Если вы не согласны с страtagsей округления printf , просто используйте round() on (copy of) percentage и заставьте свой собственный. Или вы также можете, например, sprintf() с тремя цифрами, и стереть третий.

И в вашем конкретном случае (обратите внимание, как моя система (Linux x86_64) отображает 0x419FFFFF):

 #include  #include  #include  int main(int argc, char **argv) { float percentage = 3.1415; char buffer[50]; ((uint32_t *)(&percentage))[0] = 0x419FFFFF; sprintf(buffer, "%.2f", percentage); char *p = strstr(buffer, ".00"); if (p) *p = 0x0; printf("%.15f rendered as %.2f and becomes %s\n", percentage, percentage, buffer); return 0; } 19.999998092651367 rendered as 20.00 and becomes 20 

Вместо вычисления частичной части вы можете попытаться использовать ceilf(f) == f или floorf(f) == f которые возвращают true если f является целым числом. Другой альтернативой было бы слишком использовать modf (float x, float *ipart) из std lib или fmod из math