Есть ли более элегантный способ проверить данные самой высокой/самой низкой выборки?

Вопрос N00b,

Есть ли лучший способ для читаемости/элегантности/сухости и т. д. проверять различные значения датчиков на предмет высокого/низкого значения записи? Этот код работает, но выглядит наоборот.

  void checkRecord() {

if ( temp.current > temp.high) {
  temp.high = temp.current;
}

if ( temp.current < temp.low) {
  temp.low = temp.current;
}

if ( pressure.current > pressure.high) {
  pressure.high = pressure.current;
}

if ( pressure.current < pressure.low) {
  pressure.low = pressure.current;
}
if ( humidity.current > humidity.high) {
  humidity.high = humidity.current;
}

if ( humidity.current < humidity.low) {
  humidity.low = humidity.current;
}

if ( rainfall.current > rainfall.high) {
  rainfall.high = rainfall.current;
}

if ( rainfall.current < rainfall.low) {
  rainfall.low = rainfall.current;
}
if ( altitude.current > altitude.high) {
  altitude.high = altitude.current;
}

if ( altitude.current < altitude.low) {
  altitude.low = altitude.current;
}
}

Спасибо!

, 👍1

Обсуждение

Если работает и понятно, что еще нужно? Операторы if выполняются быстро, и я сомневаюсь, что вы вызываете функцию достаточно быстро, чтобы время выполнения имело значение. В качестве альтернативы вы можете рассмотреть возможность хранения данных в массиве, а не каждой переменной отдельно - это может упростить экспорт., @MichaelT

в коде нет ничего плохого..... неправильное форматирование.... весь блок checkRecord() должен быть с отступом..... это всего лишь проблема с читабельностью..... вы могли бы записать все в одну строку операторы if .... if ( temp.current > temp.high) temp.high = temp.current; ..... тогда можно было бы аккуратно выстроить все в столбец .... поместить все знаки равенства друг под другом, @jsotola


3 ответа


0

Если бы структуры температуры, давления, влажности, осадков и высоты были элементами массива структур, вы могли бы перебирать эти элементы, устанавливая высокие и низкие значения каждого из них, используя только два рукописных оператора «если-то». Если вы также использовали перечисление для именования индексов структур, то в других частях вашего кода вы можете обращаться к каждому из них по описательному имени:

// Объявляем структуру данных и определяем их массив.
struct {
   int16_t current;
   int16_t high;
   int16_t low;
} data[5] = {0, 0, 0, 0, 0};

// Именуем структуры по индексу
enum kind {
   temperature = 0,
   pressure,
   humidity,
   rainfall,
   altitude
};


// Назначаем один тип данных:
data[temperature].current = getTermperature();


// Устанавливаем максимумы & минут для всех типов данных:
for( i = 0; i < sizeof(data)/sizeof(data[0])); ++i ){
   if ( data[i].current > data.high) {
      data[i].high = data[i].current;
   }

   if ( data[i].current < data[i].low) {
      data[i].low = data[i].current;
   }
}

Обновление:

Я борюсь с частью data[5] {0,0...} в структуре.

Я не вижу вашего эскиза целиком, но вы, вероятно, выделили 5 отдельных структур с именами «temp», «pressure», ... и т. д. Я предлагаю вам выделить массив из 5 структур (которые я в совокупности назвал «данные»), по одному для каждого из ваших индивидуальных. Я включил инициализатор ( '= {0,0,0,0,0}'), чтобы обнулить все перед началом выполнения.

все типа перечисления{} и как они становятся данными[давлением] и т. д.,

Перечисление — это быстрый способ создать 5 символов, обозначающих последовательные целые числа, в данном случае индекс в массиве каждой структуры, используя описательное имя для данных этой структуры. Таким образом, «data[pressure]» — это то же самое, что data[1] (в данном случае), но более понятно.

размер(данные)/размер(данные[0]) в цикле

Это выражение дает количество структур в массиве (общий размер массива в байтах, разделенный на размер одной структуры в байтах). Вместо этого мы могли бы написать «5», но когда вы когда-нибудь добавите еще один или два члена (возможно,wind_direction,wind_speed?), вам придется не забыть также исправить цикл for(). Используя этот расчет, компилятор сделает это за вас, оставив вам на одну возможность допустить ошибку, которую потом придется отлаживать, меньше.

и, наконец, я думаю height.high в операторе if — это опечатка? должно быть данные[i].высокие?

Абсолютно верно! Исправлено.

Обновление:

Для определения начальных значений вы можете просто присвоить начальное значение в такая структура, как int16_t low = INFINITY; и так далее вместо {0,0,0,0,0}?

Да — не зная ваших данных и приложения, я выбрал самый простой инициализатор. Полный синтаксис для выполнения того, что вы хотите, будет выглядеть так:

// Объявляем структуру данных и определяем их массив.
struct {
   int16_t current;
   int16_t high;
   int16_t low;
} data[5] = {
  {0, 0, INFINITY},
  {0, 0, INFINITY},
  {0, 0, INFINITY},
  {0, 0, INFINITY},
  {0, 0, INFINITY}
};

Вам не нужно (и не может быть) указывать каждый тип данных и имя; объявление структуры уже предоставляет эту информацию. Инициализаторы являются позиционными, и каждый из них должен быть совместим с типом данных, которому он соответствует.

,

Спасибо, я некоторых вещей не понимаю, потому что n00b. Я борюсь с частью data[5] {0,0...} в структуре. все виды перечисления {} и как они становятся данными [давление] и т. д., размер (данные)/размер (данные [0]) в цикле и, наконец, я думаю, что высота.высокая в операторе if - это опечатка вставки? должно быть data[i].high?, @opt10n

Огромное спасибо, объяснение enum kind{} и выражения в цикле очень помогло понять, как все это сочетается друг с другом. Для определения начальных значений вы можете просто присвоить начальное значение в структуре, например int16_t low = INFINITY; и так далее вместо {0,0,0,0,0}? Поскольку значение по умолчанию 0 для низкого значения не будет работать должным образом, если температура выше нуля., @opt10n


2

Вы можете написать что-то вроде:

temp.high = (temp.current > temp.high) ? temp.current : temp.high;
temp.low  = (temp.current < temp.low) ? temp.current : temp.low;
...

В большинстве случаев макросы min/max уже определены, например:

#define MAX(a, b)   ((a > b) ? a : b)
#define MIN(a, b)   ((a < b) ? a : b)

Тогда вы можете просто написать:

temp.high = MAX(temp.current, temp.high);
temp.low  = MIN(temp.current, temp.low);
...

Что расширяется до точного кода, указанного выше.

,

Я достигаю цели выглядеть немного опрятнее... Спасибо!, @opt10n

Джефф Вахаус, ты можешь пойти еще дальше. Можете ли вы сделать для этого макрос с числами с плавающей запятой?, @Jot

К сожалению, этот способ медленнее, поскольку в каждом цикле обновляются значения temp.high и temp.low. Исходный код обновлял это значение только тогда, когда условия были истинными., @Filip Franik

@FilipFranik на самом деле, это **точно** так же быстро, как операторы if. Компилятор, похоже, способен его оптимизировать., @Jot

Да, оптимизатор видит «a=a» и оптимизирует его, если вы не объявите «a» изменчивым., @Jeff Wahaus

Эти макросы уже определены в Arduino.h, но они пишутся строчными буквами: min() и max()., @Edgar Bonet


4

Это вариация идеи struct с объектно-ориентированным подходом.

Если вы поместите текущие, нижние и верхние значения любого датчика в struct, вы также можете преобразовать эту struct в класс и передать ему метод update(), который, помимо обновления текущего значения, обновляет минимум и максимум:

class LowHigh
{
public:
    LowHigh() : current(0), low(INFINITY), high(-INFINITY) {}
    void update(float value) {
        current = value;
        if (current < low)
            low = current;
        if (current > high)
            high = current;
    }
    float get_low() { return low; }
    float get_high() { return high; }
private:
    float current, low, high;
};

Я предполагаю здесь данные float, возможно, вам придется адаптироваться к любому типу подходит для ваших датчиков.

Вы можете использовать этот класс следующим образом:

< pre class="lang-c++ Prettyprint-override">НизкаяВысокая температура, давление, влажность, осадки, высота; недействительный цикл() { temp.update(temp_sensor.get_reading()); Pressure.update(pressure_sensor.get_reading()); влажность.обновление(humidity_sensor.get_reading()); // ... }
,

Мне это нравится, может потребоваться небольшая переработка моего кода, но класс Sensor — это именно то, что мне следует делать, чтобы изучить ООП и не думать о вещах так процедурно. Спасибо за ваш пример! Мне нравится INFINITY для установки начального максимума/минимума, я использовал большие и маленькие значения, выходящие за пределы диапазона., @opt10n

Я отредактировал ваш ответ, чтобы аргумент метода обновления был плавающим, а не целым. Хорошее объяснение., @Michel Keijzers

Спасибо @MichelKeijzers, это была моя оплошность., @Edgar Bonet