Как округлить миллис () при делении на минуты?

unsigned long milliseconds=millis();
// если во время чтения указанные выше миллисекунды = 599999, т.е. 1 миллисекунда меньше 600000, т.е. 10 минут
unsigned long minutes = (milliseconds/1000)/60;
// это вернет 9 вместо 10.

Как округлить результат до 10 минут? Я не имею в виду добавление 1 к конечному результату. Это должно быть в рамках расчета.

, 👍0


4 ответа


-1

Вот простой трюк, как переключиться с целочисленной математики на математику с плавающей запятой и использовать функцию округления.

  unsigned long milliseconds = 599999;

  unsigned long minutes_long = (milliseconds/1000)/60;
  // минуты_длинные = 9

  double minutes_double = (milliseconds/1000.0)/60.0;
  // минуты_двойные = 9,99998...

  double minutes_rounded = round(minutes_double);
  // минуты_округлено = 10

Также существует прием, который позволяет вычислять round с помощью целочисленной математики. Идеально, если у вас недостаточно памяти для приведения.

  unsigned long milliseconds;

  milliseconds = 600000 - 30*1000 - 1;
  //миллисекунды = 569999

  unsigned long minutes_9 = (milliseconds+30000)/60000;
  // минуты_9 = 9

  milliseconds = 600000 - 30*1000;
  //миллисекунды = 570000

  unsigned long minutes_10 = (milliseconds+30000)/60000;
  // минуты_10 = 10
,

попробуйте double minute_double = (миллисекунды/1000,0)/60,0;, @Juraj


-2

Я предполагаю, что округление внутри языка требует объявления как double или приведения к double (и затем, при необходимости, приведения «обратно» на длинный без знака). Округление не является процессом, концептуально связанным с целочисленной арифметикой. Результаты не всегда легко предсказуемы. Я привожу наглядный пример округления неотрицательных чисел в вашем контексте. (Эффект приведения зависит от компилятора, он либо усекает, либо округляет, но это работает в обоих случаях.)

double millisecs = 599999L;
double minutes = (millisecs / 1000) / 60;
unsigned mins_rnd = minutes;
mins_rnd += minutes - mins_rnd < 0.5 ? 0 : 1;
printf("%f\t%f\t%d\n", millisecs, minutes, mins_rnd);
,

это не правильный путь, @Juraj


-1

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

unsigned long milliseconds = millis();
unsigned long millisec_quo = milliseconds / 60000;
unsigned long millisec_rem = milliseconds % 60000;
unsigned long minutes = millisec_quo + (millisec_rem < 30000 ? 0 : 1);
,

Это слишком сложный способ, описанный другими., @the busybee


2

Чтобы округлить до ближайшего X в арифметике с фиксированной запятой: добавьте 1/2 X (в основных единицах, в данном случае мс) и разделите на X (опять же, в основных единицах), поэтому: миллисекунды = (миллисекунды + (30*1000L))/(60*1000L);

Добавление 1/2 X приводит к переносу одного целого X, если дробное значение X в исходном количестве было 1/2 X или больше. (Аналогичным образом, если дробное значение X меньше 1/2 X, переноса не будет).

При целочисленном делении любые дробные числа естественным образом усекаются, поэтому у вас останется округленный целочисленный результат.

,