Есть ли более элегантный способ проверить данные самой высокой/самой низкой выборки?
Вопрос 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;
}
}
Спасибо!
@opt10n, 👍1
Обсуждение3 ответа
Если бы структуры температуры, давления, влажности, осадков и высоты были элементами массива структур, вы могли бы перебирать эти элементы, устанавливая высокие и низкие значения каждого из них, используя только два рукописных оператора «если-то». Если вы также использовали перечисление для именования индексов структур, то в других частях вашего кода вы можете обращаться к каждому из них по описательному имени:
// Объявляем структуру данных и определяем их массив.
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
Вы можете написать что-то вроде:
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
Это вариация идеи 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
, возможно, вам придется адаптироваться к любому типу
подходит для ваших датчиков.
Вы можете использовать этот класс следующим образом:
LowHigh temp, pressure, humidity, rainfall, altitude;
void loop()
{
temp.update(temp_sensor.get_reading());
pressure.update(pressure_sensor.get_reading());
humidity.update(humidity_sensor.get_reading());
// ...
}
Мне это нравится, может потребоваться небольшая переработка моего кода, но класс Sensor — это именно то, что мне следует делать, чтобы изучить ООП и не думать о вещах так процедурно. Спасибо за ваш пример! Мне нравится INFINITY для установки начального максимума/минимума, я использовал большие и маленькие значения, выходящие за пределы диапазона., @opt10n
Я отредактировал ваш ответ, чтобы аргумент метода обновления был плавающим, а не целым. Хорошее объяснение., @Michel Keijzers
Спасибо @MichelKeijzers, это была моя оплошность., @Edgar Bonet
- Как объявить массив переменного размера (глобально)
- Как повторить кусок кода
- Arduino Мигает двумя светодиодами без задержки (количество повторений)
- Каковы традиционные способы оптимизации использования программной памяти?
- Как включить максимальное удаление мертвого кода?
- Как увеличить срок службы EEPROM?
- Лучшая практика — объявлять «статичный» текст и экономить память
- Как быстро и без задержки переместить сервопривод?
Если работает и понятно, что еще нужно? Операторы
if
выполняются быстро, и я сомневаюсь, что вы вызываете функцию достаточно быстро, чтобы время выполнения имело значение. В качестве альтернативы вы можете рассмотреть возможность хранения данных в массиве, а не каждой переменной отдельно - это может упростить экспорт., @MichaelTв коде нет ничего плохого..... неправильное форматирование.... весь блок
checkRecord()
должен быть с отступом..... это всего лишь проблема с читабельностью..... вы могли бы записать все в одну строку операторыif
....if ( temp.current > temp.high) temp.high = temp.current;
..... тогда можно было бы аккуратно выстроить все в столбец .... поместить все знаки равенства друг под другом, @jsotola