сравнение во временной последовательности

В скетче Arduino пользователю предлагается ввести число, представляющее время в формате ЧЧ:ММ. Это число должно быть добавлено в конец упорядоченной и ограниченной последовательности времен.

--первый ввод (нижний предел) может быть в любое время в течение 24 часов,

--верхний предел рассчитывается как нижний_предел+период; период может быть 1, 2, 3, 4, 6, 8, 12 или 24 часа,

--а чтобы быть принятым, входные данные должны соответствовать хронологическому положению предыдущего элемента и находиться в пределах заданного периода;

Например, если первый элемент — 20:00, а период — 8, то верхний предел будет 20+8=28, что составляет 04:00; принимаются значения 21:00 и 03:00, а значения 19:00, 05:00, 09:00, 17:00, ... отклоняются.

Без какой-либо информации о «дне» я не нашел подходящего алгоритма, и ни одна из доступных библиотек Arduino в этом случае не пригодится.

любая ссылка или подсказка,...

, 👍0

Обсуждение

Вводятся ли числа через Serial? Верно ли, что в первом примере будет принято любое время от 20:01 до 04:00 включительно?, @Maximilian Gerhardt

Мне это напоминает домашнее задание..., @Majenko

Совет: работа занимает считанные минуты. Оператор деления по модулю (%) — ваш лучший друг., @Majenko

@maximilian-gerhardt: числа вводятся с помощью кнопок... принимаются любые числа от 20:01 до 04:00, если они находятся хронологически после последнего элемента перед верхним пределом..., @moyoumos

У вас тут множество проблем: как ввести время, как перевести это время в минуты, как правильно сравнить эти значения. Решайте задачи по одной за раз., @Majenko

Так вы сказали, что уже решили проблему?, @Maximilian Gerhardt

@majenko: извините, я не предоставил достаточно информации... единственная проблема в том, как правильно сравнивать эти времена..., @moyoumos

@maximilian-gerhardt: работа в минутах дает простое представление о времени, но не решает проблему... применительно к примеру верхний предел все еще меньше нижнего предела: [от 20:00 до 04:00] становится [от 1200 до 240]..., @moyoumos

if (start < end) { // проверить, больше ли оно начала *и* меньше ли конца } else { // проверить, больше ли оно начала *или* меньше ли конца }, @Majenko


1 ответ


Лучший ответ:

0

Вот основная идея и пример реализации решения проблемы:

Проблема заключается в следующем: если задано начальное время time1 и период period, каждый из которых описывается парой (час,минута), как можно проверить, находится ли другое время time2 в пределах от time1 до time1 + period?

Во-первых, мы видим, что, имея пару (час, минута), мы можем вычислить общее количество минут как totalMinutes = 60*час + минута.

Затем мы можем заметить, что есть два отдельных случая, которые мы должны проверить:

  • Весь «период проверки времени», то есть от time1 до time1 + period, находится в диапазоне от 00:00 до 24:00 без выхода за пределы 24:00 при простом сложении времени. Тогда мы можем использовать простую проверку границ, сформулированную как «time2 должно быть больше time1 и меньше или равно time1 + period при сравнении общего количества минут».
  • time1 + period переполняется после 24:00. Рассмотрим пример time1 = 20:00 и period = 8:00. Таким образом, все допустимые значения времени находятся в диапазоне от 20:00 до 04:00 с неявным «циклическим переходом» от 24:00 до 00:00. Видим, что теперь необходимо проверить два временных интервала: всё с 20:01 до 24:00 и с 00:00 до 04:00 является допустимым. Таким образом, мы можем снова вывести границы в минутах. Мы можем получить 04:00, вычислив 20:00 + 08:00 по модулю 24:00. Оператор языка C % используется для вычисления остатка от деления на определённое число. Например, 28 % 24 = 4, поскольку 28 / 24 = 1 остаток 4. Это называется модульной арифметикой.

Следующая программа на C++ демонстрирует решение:

#include <cstdio>

/* returns whether time2 defined by hour2:minute2 is within the period time1 = hour1:minute1 to time1 + period. */
bool is_time_within_period(
    int hour1, int minute1, 
    int hour2, int minute2,
    int periodHour, int periodMinute) {

        //Отклонить мусорный ввод
        if(hour1 > 24 || hour2 > 24 
            || minute1 > 60 || minute2 > 60
            || periodHour > 24 || periodMinute > 60) {
                //TODO выдает сообщение об ошибке
                return false;
        }

        //Переводим часы и минуты в абсолютные минуты. Один час равен 60 минутам.
        int time1Minutes = 60 * hour1  + minute1;
        int periodMinutes = 60 * periodHour + periodMinute;
        int time2Minutes  = 60 * hour2 + minute2;

        int periodEnd = time1Minutes + periodMinutes;

        //Если время начала плюс время периода превышают 24:00, то имеет место циклический переход, который необходимо учитывать.
        bool wrapAround = false;
        if( periodEnd > (24 * 60)) {
            wrapAround = true;
        }

        bool result = false;

        //printf("Перенос: %d Конец периода %d\n", wrapAround, periodEnd);

        if(!wrapAround) {
            //если нет циклического перехода, мы можем просто сравнить общее количество минут друг с другом
            //время1 должно быть после времени2, но до (время1 + период).
            result = time2Minutes <= (time1Minutes + periodMinutes) && time2Minutes > time1Minutes;
        } else {
            //Произошёл циклический переход, т.е. время начала + период вышли за пределы 24:00.
            //Нам нужно сделать два сравнения: находится ли это в промежутке времени от time1Minutes до 24:00?
            result = time1Minutes < time2Minutes && time2Minutes <= (24 * 60);

            //результат также может быть приемлемым, если он находится в диапазоне от 00:00 до оставшегося периода
            //Используйте оператор модуля. Это преобразует, например, 28:00 в 04:00 (по модулю 24 часа, вычисленного в минутах).
            int upper = (periodEnd % (24 * 60));
            //printf("Верхний: %d (%02d:%02d)\n", верхний, (верхний / 60), верхний % 60);
            result |= time2Minutes >= 0 && time2Minutes <= upper;
        }

        return result;
}

int main() {

    const int hourStart = 20;
    const int minuteStart = 0;

    const int periodHours = 8;
    const int periodMinutes = 0;

    //поиграйтесь с этими значениями
    const int compareTimeHour  = 4;
    const int compareTimeMinute = 0;

    printf("Start: %02d:%02d\n", hourStart, minuteStart);
    printf("Period: %02d:%02d\n", periodHours, periodMinutes);
    printf("Check time: %02d:%02d\n", compareTimeHour, compareTimeMinute);


    bool res = is_time_within_period(hourStart, minuteStart, compareTimeHour, compareTimeMinute, periodHours, periodMinutes);

    if(res) {
        printf("Time is within bounds\n");
    } else {
        printf("Time is not within bounds\n");
    }

    printf("Hello\n");

    return 0;
}

Функция is_time_within_period не имеет зависимостей и поэтому может быть скопирована и вставлена в любой скетч Arduino.

Пусть время начала будет 20:00, а период — 04:00. Тогда, если мы дадим программе разные значения времени для сравнения, мы увидим, что она действительно работает.

Start: 20:00
Period: 08:00
Check time: 20:00
Time is not within bounds

Start: 20:00
Period: 08:00
Check time: 20:01
Time is within bounds

Start: 20:00
Period: 08:00
Check time: 04:00
Time is within bounds

Start: 20:00
Period: 08:00
Check time: 04:01
Time is not within bounds
,

все было очень просто: если в интервале сравнения есть циклический переход, то мы делим этот интервал на два в точке этого цикла... спасибо и +5..., @moyoumos

Функция is_time_within_period не имеет зависимостей и поэтому может быть скопирована и вставлена в любой скетч Arduino., @moyoumos