sprintf масштабирование целых чисел.123 печать как 12,3 - PullRequest
0 голосов
/ 02 января 2019

У меня есть целое число, представляющее десятые доли.Вместо деления на 10, что приводит к ошибкам округления (и потере времени), существует ли быстрый способ добавления десятичной точки перед последней цифрой?

Некоторая магия, такая как

snprintf(dest,len,"%d4.-1", 123) resulting in 12.3

причина состоит в том, чтобы избежать ошибок округления, например, в деньгах, когда сумма рассчитывается внутренне как целые центы, а не дроби в £, € или $.

Если я правильно помню свой COBOL, здесь можно указатьтакой формат, как 9 990,00, в котором 1234 печатается как 12,34, а 1 - как 0,01.

void setup() {
  Serial.begin(115200);
  delay(1000);
  uint16_t i16 = 0;
  float f = 998;
  for (i16 = 998; i16 < 1011; i16++) {
    Serial.print(i16 / 1000);
    Serial.print(" ");
    Serial.print(f / 1000);
    Serial.printf("  %0.3f %0.3f %0.7f\n",i16/1000,f/1000,f/1000);
    f = f + 1;
  }
}

int / 10 по-прежнему int, поэтому 123/10 = 12.

Странно fprint("%0.2f",123/10) печатает 0.00

0 1.00 0.000 0.998 0.9980000 0 1.00 0.000 0.999 0.9990000 1 1.00 0.000 1.000 1.0000000 1 1.00 0.000 1.001 1.0010000 1 1.00 0.000 1.002 1.0020000 1 1.00 0.000 1.003 1.0030000 1 1.00 0.000 1.004 1.0039999 <--- Rounding error 1 1.00 0.000 1.005 1.0050000 1 1.01 0.000 1.006 1.0060000 1 1.01 0.000 1.007 1.0070000 1 1.01 0.000 1.008 1.0080000 1 1.01 0.000 1.009 1.0089999 <--- Rounding error 1 1.01 0.000 1.010 1.0100000

% 0,6f не дает ошибок округления, но% 0,7f делает.

Так что для дробных целых чисел это будетбыло бы неплохо иметь целочисленный формат со смещенной десятичной точкой.

Использование поплавков иногда может дать некоторые забавные результаты, только вчера я видел «Ожидается, что вода поднимется между 10,000000002 и 12 футами».

Ответы [ 3 ]

0 голосов
/ 02 января 2019

Убедитесь, что у вас достаточно места в dest!

int n = snprintf(dest, len, "%d", 123);
dest[n + 1] = 0;
dest[n] = dest[n - 1];
dest[n - 1] = '.';

или, сохранив одну строку кода (спасибо @bruno)

int n = snprintf(dest, len, "%d#", 123);
dest[n - 1] = dest[n - 2];
dest[n - 2] = '.';
0 голосов
/ 04 января 2019

Обратите внимание, что при fprint("%0.2f",123/10) код OP имеет неопределенное поведение из-за несоответствия между типом double, ожидаемым спецификатором преобразования %f, и значением int 123/10.

Целочисленное деление четко определено и не подвержено ошибкам округления. Стандартная библиотека C предоставляет функции div(), ldiv(), and lldiv() для вычисления целочисленного деления и остатков в одной операции, так почему бы не воспользоваться преимуществами?

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    for (int i = 0; i < 1010; i += 500) {
        for (int j = 0; j < 10; j++) {
            int num = i + j;
            div_t val = div(num, 10);
            printf("%d --> %d.%d\n", num, val.quot, val.rem);
        }
    }

    return 0;
}

Вывод программы:

0 --> 0.0
1 --> 0.1
2 --> 0.2
3 --> 0.3
4 --> 0.4
5 --> 0.5
6 --> 0.6
7 --> 0.7
8 --> 0.8
9 --> 0.9
500 --> 50.0
501 --> 50.1
502 --> 50.2
503 --> 50.3
504 --> 50.4
505 --> 50.5
506 --> 50.6
507 --> 50.7
508 --> 50.8
509 --> 50.9
1000 --> 100.0
1001 --> 100.1
1002 --> 100.2
1003 --> 100.3
1004 --> 100.4
1005 --> 100.5
1006 --> 100.6
1007 --> 100.7
1008 --> 100.8
1009 --> 100.9
0 голосов
/ 02 января 2019
snprintf (dest, len, "%3d.%01d", 123/10, 123%10)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...