Как округлить миллис () при делении на минуты?
unsigned long milliseconds=millis();
// если во время чтения указанные выше миллисекунды = 599999, т.е. 1 миллисекунда меньше 600000, т.е. 10 минут
unsigned long minutes = (milliseconds/1000)/60;
// это вернет 9 вместо 10.
Как округлить результат до 10 минут? Я не имею в виду добавление 1 к конечному результату. Это должно быть в рамках расчета.
@Hilton, 👍0
4 ответа
Вот простой трюк, как переключиться с целочисленной математики на математику с плавающей запятой и использовать функцию округления.
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
или приведения к 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
Вот еще одна версия, использующая только целочисленную арифметику:
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
Чтобы округлить до ближайшего X в арифметике с фиксированной запятой: добавьте 1/2 X (в основных единицах, в данном случае мс) и разделите на X (опять же, в основных единицах), поэтому:
миллисекунды = (миллисекунды + (30*1000L))/(60*1000L);
Добавление 1/2 X приводит к переносу одного целого X, если дробное значение X в исходном количестве было 1/2 X или больше. (Аналогичным образом, если дробное значение X меньше 1/2 X, переноса не будет).
При целочисленном делении любые дробные числа естественным образом усекаются, поэтому у вас останется округленный целочисленный результат.
- Как использовать SPI на Arduino?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- Как создать несколько запущенных потоков?
- Как подключиться к Arduino с помощью WiFi?
- avrdude ser_open() can't set com-state
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Я закирпичил свой Arduino Uno? Проблемы с загрузкой скетчей на плату
попробуйте
double minute_double = (миллисекунды/1000,0)/60,0;
, @Juraj