Работа с инкрементом/декрементом

mixon
Offline
Зарегистрирован: 19.04.2019

Всем привет! Есть такой код:

void loop() 
{
  
  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 1); 
  Serial.print(" r"); 
  Serial.println();
  
   
  if (scale.get_units() > 100)
  {
  level--;
  }

  
  else if (scale.get_units() < 60)
  {
  level++; 
  }

  else 
  {
  int level = 180;
  }
  
}

Здесь нужно задать пределы инкрементирования и декрементирования как 0 и 240 соответственно. Т.е. чтобы level инкрементировался, но доходя до 240 останавливался бы на этом значении. Так же и с декрементом - чтобы level не уходил ниже нуля. Как это можно лучше сделать?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

mixon пишет:

Как это можно лучше сделать?

Составить нормальный алгоритм и по нему написать программу. Ваша программа не выдерживает даже минимальной критики. Сотрите и напишите по новой согласно алгоритму.

mixon
Offline
Зарегистрирован: 19.04.2019

Не правильно написал: "Здесь нужно задать пределы инкрементирования и декрементирования как 240 и 0 соответственно." - это верно.

mixon
Offline
Зарегистрирован: 19.04.2019

mykaida,

А есть возможность ограничить инкрементирование каким-то пределом?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

mixon пишет:

mykaida,

А есть возможность ограничить инкрементирование каким-то пределом?

Можно

if(level>240) level=240;

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

mykaida пишет:

mixon пишет:

mykaida,

А есть возможность ограничить инкрементирование каким-то пределом?

Можно

if(level>240) level=240;

что мешает просто не допускать инкремента больше 240, чем делать и сбрасывать его?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

xDriver пишет:

что мешает просто не допускать инкремента больше 240, чем делать и сбрасывать его?

В данном случае, сэр, я пошел на поводу наглядности. Конечно можно и так:

else if ((scale.get_units() < 60)&&(level<240))
  {
  level++;
  }

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Вместо 

level++;

пишем что-то вроде

level += level < 240;

(применительно к коду из исходного сообщения)

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

andriano пишет:

level += level < 240;

"В моем доме попрошу такие слова не произносить!"

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Действительно в Вашем доме?

Тогда приношу свои извенения.

Хочу лишь отметить, что предложенный вариант не имеет тех недостатков, которые присущи вариантам, опубликованным ранее, в частности:

- нет лишнего ветвления по сравнению с вариантом в сообщении №4,

- невозможен побочный эффект из-за сокращения количества вызовов метода класса как в сообщении №6.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:
предложенный вариант не имеет
А какая разница имеет или не имеет? Переменная level в том scope один хрен не описана :(

sadman41
Offline
Зарегистрирован: 19.10.2016

andriano пишет:

- нет лишнего ветвления по сравнению с вариантом в сообщении №4,

Компилятор сгенерирует asm-код тоже без джампа по условию (просто интересно)?

mixon
Offline
Зарегистрирован: 19.04.2019

Спасибо всем за ответы

andriano пишет:

Вместо 

level++;

пишем что-то вроде

level += level < 240;

(применительно к коду из исходного сообщения)

andriano,

Мне понравился ваш вариант. Он работает.

Интересно узнать об операторе +=, я прочитал, что он имеет такой смысл:

A+=B эквивалентно A = A + B.

У нас, получается, level = level + level. Т.к. A = B = level. Почему же в итоге происходит именно инкрементирование? Как в данном случае работает += оператор?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

mixon пишет:

A+=B эквивалентно A = A + B.

У нас, получается, level = level + level. Т.к. A = B = level. Почему же в итоге происходит именно инкрементирование? Как в данном случае работает =+ оператор?

нет, у нас получается level = level + условие

где условие = level < 240, оно либо истина (1), либо ложь(0), подставляем это в строку выше.

b707
Offline
Зарегистрирован: 26.05.2017

andriano - для "Песочницы" ваш код имеет один важный недостаток - новички его совершенно не понимают :)

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

mixon пишет:

Мне понравился ваш вариант. Он работает.

Интересно узнать об операторе +=, я прочитал, что он имеет такой смысл:

A+=B эквивалентно A = A + B.

У нас, получается, level = level + level. Т.к. A = B = level. Почему же в итоге происходит именно инкрементирование? Как в данном случае работает += оператор?

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

mixon
Offline
Зарегистрирован: 19.04.2019

xDriver,

Спасибо :) Понятно, получается, тут как бы выполнение условия (true (1)) - является инкрементом.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

итого у нас три предложения (пока)

1)

level++;
if (level>240) level=240;

2)

if (level<240) level++;

3)

level += level<240; 

надо у ТС спросить что ему понятнее.

Green
Offline
Зарегистрирован: 01.10.2015

1.1)

if (++level > 240) level = 240;

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

не, ну енто вариации на тему :)

1.2)

if (++level > 240) level--;

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Господа, да похрен как написать. Главное чтобы у программиста в башке был алгоритм и он его переводил на язык программирования. Оптимально - неоптимально это с опытом приходит. Мы можем 100500 раз стебаться над копирастерами, но если человек хочет разобраться, а не "памагите слить два кода" - я помогу. Но так, чтобы он прочувствовал и понял, чтобы он знал, что каждая строчка его программы делает. Не выдержит - не программист :)

nik182
Offline
Зарегистрирован: 04.05.2015

andriano пишет:

Вместо 

level++;

пишем что-то вроде

level += level < 240;

(применительно к коду из исходного сообщения)

Простите, я совсем не программист 500 уровня и я не понимаю в какой момент программа в данном выражении ограничит значение level уровнем 240. Чисто с точки зрения оператора +=   Если эта конструкция работает, то получается что сначала выполняется сравнение, а потом инкремент? Т. Е. Для начинающего, с учётом ассоциативности разбора cправа на лево эта строка должна выглядеть как level+=(level<240)? И придёт к виду if(levеl<240)level++; При не выполнении условия += будет проигнорирован? В чем будет разница в коде ассемблера? Есть ли выигрыш в такой нотации? 

Вот. Век живи, век учись... Чтой то боюсь я такого продвинутого программирования. 

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Украдено до нас?

http://arduino.ru/Reference/Constrain

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

xDriver пишет:

итого у нас три предложения (пока)

Да, там ещё можно придумать, делов-то

level = (level + 1) % 240;

и это не предел.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

b707 пишет:

andriano - для "Песочницы" ваш код имеет один важный недостаток - новички его совершенно не понимают :)

Это не бага, это - фича!

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

Но по большому счету - да: конструкция требует понимания достаточно фундаментальных вещей таких как Булева алгебра и особенности ее применения в Си. Поэтому думаю, что не только для новичков, но и для некоторых программистов, имеющих опыт, эта консрукция может оказаться интересной.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:
А когда разберется, думаю, будет для него от этого польза.
Не думаю. Скорее, вред. Не новичковое это дело - забиваться на неявные преобразования типов. Ещё в Си - куда ни шло, а в С++ - скорее вред.

Алексей.
Алексей. аватар
Offline
Зарегистрирован: 02.02.2018

nik182 пишет:
Если эта конструкция работает, то получается что сначала выполняется сравнение, а потом инкремент? Т. Е. Для начинающего, с учётом ассоциативности разбора cправа на лево эта строка должна выглядеть как level+=(level<240)? И придёт к виду if(levеl<240)level++; При не выполнении условия += будет проигнорирован?

Почти так.
Для начала нужно запомнить или записать для себя таблицу определяющую приоритеты операций, чтоб скобками не злоупотреблять.
Операция += имеет более низкий приоритет чем операция сравнения <
таким образом сначала буден получен результат операции сравнения, тип которого - логический true/false
после этого будет выполнена операция += для заданного типа, в данном случае целочисленный, параметр для операции += полученный из предыдущего вычисления т.е. true/false
фактически получаем level += 1 или level += 0
и выполнение или не выполнение условия не проверяется, просто к переменной добавляется результат предыдущей операции
 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

andriano пишет:
А когда разберется, думаю, будет для него от этого польза.
Не думаю. Скорее, вред. Не новичковое это дело - забиваться на неявные преобразования типов. Ещё в Си - куда ни шло, а в С++ - скорее вред.

Женя! Поправь меня, если я не прав. Мне казалось, что а стандарте "истина" это "не ноль", а не конкретно 1. Поэтому не уверен, что неявное преобразование выдаст именно 1, а не то, что компилятору удобнее в текущий момент.

nik182
Offline
Зарегистрирован: 04.05.2015

О! Я то как то не понял сразу что меня коробило. Я когда то ковырял код после hi-tech С компилятора PIC и там истина была 0хff. С тех пор как то в голове не лежит что 1=1 в булевой алгебре микроконтроллера равно 1.

Алексей.
Алексей. аватар
Offline
Зарегистрирован: 02.02.2018

В стандарте C99 раздел 7.16 Boolean type and values пункт 3.
true which expands to the integer constant 1,
false which expands to the integer constant 0,
and __bool_true_false_are_defined which expands to the integer constant 1.
кроме этого в пункте 4 сказано
Notwithstanding the provisions of 7.1.3, a program may undefine and perhaps then
redefine the macros bool, true, and false.
7.1.3 - это положения о зарезервированных идентификаторах
Значит если не перегружен true то должна быть единица.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula, нет, так было в С на самой заре времён. Сегодня чуть по-другому, но я не зря там сделал оговорку "в С ещё куда ни шло", разница между С и С++ есть и существенная.

С (ISO-IEC 9899-2018)
"Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specifed relation is true and 0 if it is false.) The result has type int" (6.5.8.(6), стр. 69)

Т.е. здесь в Си никакого преобразования типов не выполняется, т.к. результат сравнения уже имеет тип int: 0 или 1 (знаковый, кстати!)

А вот с С++ посложнее.

С++ (ISO-IEC 14882 - 2017)
"The type of the result is bool" (8.9.(1), стр. 133)

Т.е. здесь выражение andriano требует преобразования типа из bool в int. Правило преобразования таково:

"If the source type is bool, the value false is converted to zero and the value true is converted to one" (7.8.(4), стр. 90)

Т.е. как бы результат-то получится верный. Но рекоммендовать выражение со скрытым преобразованием новичкам в качестве примера от которого им будет польза .... по мне, так сомнительно. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Алексей. пишет:

В стандарте C99 раздел 7.16 Boolean type and values пункт 3.

Пример неудачен по двум причинам.

1. Действующий стандарт С не 99, а 18.

2. Причём тут преобразование "Boolean type", если результат операций ">", "<" и т.п. в Си вовсе не boolean, а int. Так что в С никакого преобразование просто не выполняется.

SLKH
Онлайн
Зарегистрирован: 17.08.2015

nik182 пишет:

Вот. Век живи, век учись... Чтой то боюсь я такого продвинутого программирования. 

Такая ж фигня. 

Для меня, например, сложение "integer + boolean" без особой на то необходимости представляется неким извращением. Впрочем, насколько я понимаю, в этом языке понятие стыда отсутствует полностью...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

SLKH пишет:

Для меня, например, сложение "integer + boolean" без особой на то необходимости представляется неким извращением. 

Это вы ещё не видели операции сложения денежных сумм, записанных прописью с указанием дебетовая сумма или кредитовая:)

kalapanga
Offline
Зарегистрирован: 23.10.2016

А что при конвертации int to bool? Я правильно понимаю, что ноль конвертируется в ноль (false), а всё остальное (любого знака) в единицу (true)?

Здесь похоже как раз справедливо - истина это всё, что не ноль.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

SLKH пишет:

Для меня, например, сложение "integer + boolean" без особой на то необходимости представляется неким извращением. Впрочем, насколько я понимаю, в этом языке понятие стыда отсутствует полностью...

Тут полностью поддерживаю.

Но Си - он такой, тут уж никуда не денешься.

kalapanga пишет:

А что при конвертации int to bool? Я правильно понимаю, что ноль конвертируется в ноль (false), а всё остальное (любого знака) в единицу (true)?

Здесь похоже как раз справедливо - истина это всё, что не ноль.

Да, например, способ превратить ненулевое число в единицу: MyNumber = !!MyNumber;.

sadman41
Offline
Зарегистрирован: 19.10.2016

А с объектным-то кодом что - будет он короче, если if() фактически занести в формулу или это просто красиво?

Алексей.
Алексей. аватар
Offline
Зарегистрирован: 02.02.2018

ЕвгенийП пишет:
Пример неудачен по двум причинам.
1. Действующий стандарт С не 99, а 18.

Ну тогда уж 11-й ;)
Для ардуино-иде 1.8.9 при выборе платы uno у avr-g++ вижу ключ -std=gnu++11 разве это не явное указание включения расширений стандарта
ЕвгенийП пишет:

2. Причём тут преобразование "Boolean type", если результат операций ">", "<" и т.п. в Си вовсе не boolean, а int. Так что в С никакого преобразование просто не выполняется.
Тут вы правы, результат операций целочисленный, логический тип тут не подходит, а приведение типов я указал как в стандарте логический приводится к целочисленному, видимо зря.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

kalapanga пишет:

А что при конвертации int to bool? Я правильно понимаю, что ноль конвертируется в ноль (false), а всё остальное (любого знака) в единицу (true)?

Что мешает прочитать прямую цитату из стандарта в посте #30? Последний из сдвинутых вправо абзацев?

SLKH
Онлайн
Зарегистрирован: 17.08.2015

Алексей. пишет:

nik182 пишет:
Если эта конструкция работает, то получается что сначала выполняется сравнение, а потом инкремент? Т. Е. Для начинающего, с учётом ассоциативности разбора cправа на лево эта строка должна выглядеть как level+=(level<240)? И придёт к виду if(levеl<240)level++; При не выполнении условия += будет проигнорирован?

Почти так.
Для начала нужно запомнить или записать для себя таблицу определяющую приоритеты операций, чтоб скобками не злоупотреблять.
Операция += имеет более низкий приоритет чем операция сравнения <
таким образом сначала буден получен результат операции сравнения, тип которого - логический true/false
после этого будет выполнена операция += для заданного типа, в данном случае целочисленный, параметр для операции += полученный из предыдущего вычисления т.е. true/false
фактически получаем level += 1 или level += 0
и выполнение или не выполнение условия не проверяется, просто к переменной добавляется результат предыдущей операции
 

Смотрю я на строку из соседней ветки:  if (tim[i] - 500 < millis() - last_time[i])

через полсекунды после включения ардуины и далее она будет эквивалентна  "if (tim[i] - 1 - last_time[i])" ?

Алексей.
Алексей. аватар
Offline
Зарегистрирован: 02.02.2018

SLKH пишет:
Смотрю я на строку из соседней ветки:  if (tim[i] - 500 < millis() - last_time[i])
через полсекунды после включения ардуины и далее она будет эквивалентна  "if (tim[i] - 1 - last_time[i])" ?

сложение и вычитание - приоритет 6
операции сравнения < ≤ > ≥ - приоритет 8
значит сначала выполняется tim[i] - 500 и millis() - last_time[i]
затем операция сравнения <

Алексей.
Алексей. аватар
Offline
Зарегистрирован: 02.02.2018

sadman41 пишет:
А с объектным-то кодом что - будет он короче, если if() фактически занести в формулу или это просто красиво?

class A {
public:

  A(int value = 0, int min_value = 0, int max_value = 0) {
    this->value = value;
    this->min_value = min_value;
    this->max_value = max_value;
  }

  int& operator ++(int) {
    return this->value += this->value < this->max_value;
  }

  int& operator +=(int rhs) {
    if (this->value += rhs, this->value > this->max_value) {
      this->value = this->max_value;
    }
    return this->value;
  }

  int& operator --(int) {
    return this->value -= this->value > min_value;
  }

  int& operator -=(int rhs) {
    if (this->value -= rhs, this->value < this->min_value) {
      this->value = this->min_value;
    }
    return this->value;
  }

  operator int () const {
    return this->value;
  }

  int& operator = (int rhs) {
    return (this->value = rhs < this->min_value ? this->min_value : rhs > this->max_value ? this->max_value : rhs);
  }

private:
  int value;
  int min_value;
  int max_value;
};

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println("Initialize class by value 0 and min value -3 and max value 3");
  A a(0, -3, 3);

  Serial.print("Increment test for 10 iterations: ");
  for (int x = 0; x < 10; x++, a++, Serial.print(" "), Serial.print(a)) ;
  
  Serial.println();
  Serial.print("Decrement test for 10 iterations: ");
  for (int y = 0; y < 10; y++, a--, Serial.print(" "), Serial.print(a)) ;

  Serial.println();
  a = 100;
  Serial.print("Assign a value of 100: ");
  Serial.println(a);

  a -= 100; 
  Serial.print("100 subtraction from class: ");
  Serial.println(a);
  
  a += 100; 
  Serial.print("100 addition to class: ");
  Serial.println(a);
}

void loop() {}

Вывод:


Initialize class by value 0 and min value -3 and max value 3
Increment test for 10 iterations:  1 2 3 3 3 3 3 3 3 3
Decrement test for 10 iterations:  2 1 0 -1 -2 -3 -3 -3 -3 -3
Assign a value of 100: 3
100 subtraction from class: -3
100 addition to class: 3
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Это вы ещё не видели операции сложения денежных сумм, записанных прописью с указанием дебетовая сумма или кредитовая:)

Тихонов-Козлов?

Green
Offline
Зарегистрирован: 01.10.2015

Алексей. пишет:

sadman41 пишет:
А с объектным-то кодом что - будет он короче, если if() фактически занести в формулу или это просто красиво?

class A {
public:

А, ну да. Всё ясно как божий день.)))

А если по простому, то в данном случае, без if-а короче на 2 байта.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Алексей. пишет:

ЕвгенийП пишет:
Пример неудачен по двум причинам.
1. Действующий стандарт С не 99, а 18.

Ну тогда уж 11-й ;)

Что-то мне подсказывает, что Вы Си и Си++ путаете :)

sadman41
Offline
Зарегистрирован: 19.10.2016

Green пишет:

А если по простому, то в данном случае, без if-а короче на 2 байта.

Наверняка эти два байта будут сожраны, если делать с "защитой" через value += !!(condition). Так что только буковки исходника экономятся и то в случае шага равному единице.

Green
Offline
Зарегистрирован: 01.10.2015

Буковки экономятся, понимание усложняется... Для данного компилятора защита !! не нужна. Для наглядности.
 

 7d6:	80 91 16 01 	lds	r24, 0x0116	; 0x800116 <__data_end>
 7da:	8f 5f       	subi	r24, 0xFF	; 255
 7dc:	80 93 16 01 	sts	0x0116, r24	; 0x800116 <__data_end>
 7e0:	81 3f       	cpi	r24, 0xF1	; 241
 7e2:	18 f0       	brcs	.+6      	; 0x7ea <main+0x9a>
 7e4:	80 ef       	ldi	r24, 0xF0	; 240
 7e6:	80 93 16 01 	sts	0x0116, r24	; 0x800116 <__data_end>
 
 7ea:	80 91 16 01 	lds	r24, 0x0116	; 0x800116 <__data_end>
 7ee:	91 e0       	ldi	r25, 0x01	; 1
 7f0:	80 3f       	cpi	r24, 0xF0	; 240
 7f2:	08 f0       	brcs	.+2      	; 0x7f6 <main+0xa6>
 7f4:	90 e0       	ldi	r25, 0x00	; 0
 7f6:	89 0f       	add	r24, r25
 7f8:	80 93 16 01 	sts	0x0116, r24	; 0x800116 <__data_end>

 

Green
Offline
Зарегистрирован: 01.10.2015

nik182 пишет:

Я когда то ковырял код после hi-tech С компилятора PIC и там истина была 0хff. С тех пор как то в голове не лежит что 1=1 в булевой алгебре микроконтроллера равно 1.

Какая версия htpicc?