Работа с циклами

GarryC
Offline
Зарегистрирован: 08.08.2016

Дракула, я не очень понял, Вы хотели доказать, что я прав и мой вариант быстрее? Вам это удалось.
Спасибо, но я как то и ранее в этом был уверен, что мой вариант займет меньше места и будет работать быстрее. Насколько именно - я не знал, хорошо, что  выяснили насчет 7%, хотя, если Вы посмотрите мои посты на Хабре, digitalWrite - не самый лучший заполнитель, поскольку довольно таки длинный (и random тоже), но все равно спасибо.
Так что приведенный Вами пример иллюстрирует, что я, ГарриС, совершенно прав в своих оценках, рад, что Вы в этом убедились.

Резюмирую - вариант с вычитанием против модуля 1) занимает меньше места 2) выполняется быстрее 3) понятен даже не слишком хорошо знающему язык читателю.
Внимание, вопрос - почему мы должны предпочесть вариант с % - только потому, что в нем 7 символов вместо 16 в варианте с if - или мы должны еще принять во внимание оскорбления чувств истинных программистов, не желающих общаться со всяким быдлом, которое даже оператора взятия по модулю не знает?
 

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

GarryC
Offline
Зарегистрирован: 08.08.2016

Евгений, я думал, что Вы действительно посмотрели варианты и убедились, что оператор преобразования типа решает поставленную задачу (и он дествительно быстрее, чем ужасный вариант с двумя отрицаниями, Вы правы), а выясняется, что это Вы просто так сказали, чтобы попинать MISRA и даже не огорчены, что не угадали. Простите, но Вы меня разочаровали.

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

GarryC пишет:

 чтобы попинать MISRA и 

Господь с Вами, нафига мне её пинать? Сказал в надеждн прекратить холивар.

GarryC пишет:

даже не огорчены, что не угадали. 

Кто Вам сказал, что не угадал? Вполне себе угадал, там и угадывать нечего.

GarryC пишет:

Вы меня разочаровали.

Ничем не могу помочь :(

 

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

GarryC пишет:

, если Вы посмотрите мои посты на Хабре, digitalWrite - не самый лучший заполнитель, поскольку довольно таки длинный (и random тоже),

...а если не посмотрю, то даже не узнаю, что же скрывается за digitalWrite()?

Вы не охренели в край?

Вы ведь прочитали пост, пусть и не Вам адресованный, о том, с кем разговариваете.

Вы считаете себя вправе давать совет "изучать Ваши труды"?

Вы, кстати, не представились, ни возраста ни образования, только апломб.

Думаю, что мне более неинтересно. Идите на х...абр, к профанам, пусть аплодируют стоя.

Успехов!

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

wdrakula пишет:

Идите на х...абр, к профанам, пусть аплодируют стоя.

я посылал оппонентов найух, когда это ещё не было мейнстримом.

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Клапауций 112 пишет:

wdrakula пишет:

Идите на х...абр, к профанам, пусть аплодируют стоя.

я посылал оппонентов найух, когда это ещё не было мейнстримом.

+1.

GarryC
Offline
Зарегистрирован: 08.08.2016

Меня умиляет уровень аргументации от Дракула - вначале он заявляет, что
 "Это при минимальной возможной полезной нагрузке на код, всего один оператор."
затем обнаруживается, что там три оператора, и ему мягко намекают, что даже одна строчка кода, содержащая digitalWrite - это не минимально возможная нагрузка.
То есть человек откровенно путает понятия, но вместо того, чтобы признать неточность и исправить ее, начинается разговор в стиле "А ты кто такой".

В общем то, после подобного заявления меня не очень интересует мнение данного автора, но просто для тех, кто может прочитать данный обмен комментариями - мне 56 лет, выпускник МИЭТ 1984 года, всю жизнь в профессии (вычислительные комплексы и системы), соответственно встроенным программированием занимаюсь более 30 лет,  долгое время был ИП (изготавливал аппаратуру связи), потом вернулся в найм, с 2012 по настоящее время - начальник отдела разработки. 
И вот просто интересно, каким образом то, что я только что написал, может повлиять на время выполнения операции digitalWrite, либо на ее исходный код.

Относительно того, что на Хабре профаны - ну не все же достигли столь выдающихся успехов в жизни, как Дракула (а можно ссылочки на патенты, разработанные изделия, страничку Github либо что угодно, что подтвердит Ваши успехи в области электроники), мне многие материалы на этом ресурсе кажутся интересными и не тривиальными, но это опять таки, с позиций откровенного неудачника рядом с титаном мысли.

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

Мужики, да прекратите Вы фаллометрию, наконец. ну, взрослые ж дядьки!

GarryC
Offline
Зарегистрирован: 08.08.2016

Евгений, "если бы это не могли увидеть дети", то мне было бы глубоко по фиг на мнение подобного оппонента, тем более мнение неправильное.
Но он то не мне (мне туфту впаривать бесполезно, не впаришь), он другим читателям форума, в том числе малоопытным, туфту гонит, и в этом то все и дело.

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

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

Мужики, да прекратите Вы фаллометрию, наконец. ну, взрослые ж дядьки!

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

ну и где  еще почитаешь, что думают о тебе люди с IQ 160... мой официальный результат IQ =71...

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

1. Любезнейший ГарриС! Мы же не будем ставить на одну доску "заборостроительный техникум", в котором Вы изволили учиться... да еще, по простейшим расчетам, после армии (а это уже диагноз) ;)  с МехМатом МГУ?

Ну это ладно, это к фаллометрии относилось. Я ее прекращаю.

....

Гарри. Я ничего против Вас не имею, и не собирался никак Вас задевать. Просто я "ершистый".

Да и против Вашего кода ничего не имею.

Меня зацепил только апломб, что писать нужно "так и только так!".

Евгений попробовал один раз сказать, что есть контроллеры с аппаратным делением. Я добавил, что читаемость и логика кода бывают важнее экономии пары тактов, но Вы уже "сели на коня".

Вы же написали, что готовы поступиться эффективность ради своих убеждений? Я про union.

Вот и я готов поступиться эффективностью, ради логики кода. Если мне нужен остаток, так и надо писать.

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

Но, при необходимости, можно оптимизировать. Недавний пример - у человека не помещался какой-то приемник в тиньку13. Там есть секрет, как избавиться от этой самой математики в коде. На чем экономится больше 100 байт, из 1КБ тиньки.

Я сейчас поищу ту ветку. Просто чтобы Вы меня говном не поливали.

Вот эта ветка.

Код в сообщ. 44. Вот так можно оптимизировать под ограничения контроллера. ИМХО - это хороший пример.

И это я, прошу заметить, старался как можно меньше менять творение автора, чтобы он сохранял понимание.

Если нет нужды в оптимизации - нужно вызывать миллис и микрос, если пришлось - от них нужно избавляться.

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

====

Еще раз - мне жаль, что мы ругаемся. Очень мало програмистов на форуме, а тех, кто по профессии программист - еще меньше. Даже при расхождении в "религии" не стоит ругаться.

Я признаю, что не являюсь носителем "бесспорной истины", сделайте милость - повторите это про себя.

GarryC
Offline
Зарегистрирован: 08.08.2016

1. А с каких пор МИЭТ стал "заборостроительным техникумом" - он всегда был и остается одним из ведущих технических вузов страны - ну это мое мнение, но оно совпадает с мнением большинства.
И насчет расчетов - я чего то недопонял : 2017 год - 56 = 1961 год рождения + 16 лет = 1978 год поступления + 6 лет = 1984 год окончания - я не вижу места для армии (хотя соглашусь, у нас в группе были ребята после армии, особо не блистали) - что я посчитал на так (или на мехмате другая арифметика).
У меня были знакомые по работе, закончившие ВМК (приматы, по их терминологии), нормальные ребята, но сверх-звездами я  бы их все таки не назвал - это про фаллометрию.

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

А вот насчет union в частности и MISRA вообще - там каждый набор правил предваряется текстом на 1-3 страницы, где объясняется, почем то или иное решение в С небезопасно и к чему оно может привести - и лишь потом идут 1-5 правил на пол-страницы все. Не надо ругать правила, не прочитав их обоснований. И к union там есть реальная претензия - они сильно зависят от порядка байтов в слове, поэтому небезопасны, и это правда. А подход со сдвигами будет работать всегда - но он уступает по эффективности, поэтому и применяют все (и я в том числе) системо-зависимые макросы, чтобы совместить универсальность с эффективностью.

=====

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

GarryC
Offline
Зарегистрирован: 08.08.2016

b707, Вы не ошиблись - при таком значении IQ функции чтения и написания едва ли могут быть осуществленны - если разве что Вы выражаете свои мысли жестами и мычанием, а некий добрый самаритянин переводит их на бумагу?

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

b707 пишет:

Нет-нет-нет, Евгений - ну интересно же читать! 

А легко! Не холивара окаянного ради, но исключительно просвещения для ... :)

GarryC,

я готов объяснить Вам, почему Вы неправы, несмотря на Ваш пост #43 с казалось бы неопровержимыми доказательствами.

В Вашем посте #43 Вы допустили две ошибки (у меня нет сомнений, что речь идёт об ошибках, а не об умышленной подтасовке - никаких сомнений, так что не воспринимайте это как наезд, пожалуйста).

Первая ошибка на самом деле ни на что не влияет и результат не изменяет, но всё же ... в задаче речь шла о двухбайтовом типе int, а Вы использовали однобайтовый. Но это на результат не влияет.

А вот вторая ошибка ... в изначальной задаче речь шла о переменной типа int, а вовсе не о volatile int. Я понимаю, что Вы использовали volatile, чтобы не позволить оптимизатору просто выбросить ВСЁ за ненадобностью, но этим Вы исказили конечный результат исследования, т.к. связали оптимизатор по рукам и ногам. В таких случаях надо не volatile вставлять, а использовать полученные значения, не позволяя оптимизатору всё выбросить, но и не связывая его в его действиях.

Я подготовил для Вас вот такой пример:

void setup() {
	{
		int n = analogRead(1);
		if (n != 0) n = 1;
		Serial.print(n);
	}
	{
		int n = analogRead(1);
		n = (bool) n;
		Serial.print(n);
	}
	{
		int n = analogRead(1);
		n = !! n;
		Serial.print(n);
	}
}
void loop() {
}

Вы согласны, что он вполне корректен?

Я компилировал его в IDE 1.8.1 с опциями оптимизации, установленными по умолчанию (из коробки).

Теперь смотрим на листинг.

  23               		.loc 1 3 0
  24 0000 81E0      		ldi r24,lo8(1)
  25 0002 0E94 0000 		call analogRead
  26               	.LVL0:
  27               		.loc 1 4 0
  28 0006 61E0      		ldi r22,lo8(1)
  29 0008 70E0      		ldi r23,0
  30 000a 892B      		or r24,r25
  31 000c 01F4      		brne .L2
  32 000e 60E0      		ldi r22,0
  33 0010 70E0      		ldi r23,0
  34               	.L2:
  35               		.loc 1 5 0
  36 0012 4AE0      		ldi r20,lo8(10)
  37 0014 50E0      		ldi r21,0
  38 0016 80E0      		ldi r24,lo8(Serial)
  39 0018 90E0      		ldi r25,hi8(Serial)
  40               	.LVL1:
  41 001a 0E94 0000 		call _ZN5Print5printEii
  42               	.LVL2:
  43               	.LBE2:
  44               	.LBB3:
  45               		.loc 1 8 0
  46 001e 81E0      		ldi r24,lo8(1)
  47 0020 0E94 0000 		call analogRead
  48               	.LVL3:
  49               		.loc 1 9 0
  50 0024 61E0      		ldi r22,lo8(1)
  51 0026 892B      		or r24,r25
  52 0028 01F4      		brne .L3
  53 002a 60E0      		ldi r22,0
  54               	.L3:
  55               	.LVL4:
  56 002c 70E0      		ldi r23,0
  57               		.loc 1 10 0
  58 002e 4AE0      		ldi r20,lo8(10)
  59 0030 50E0      		ldi r21,0
  60 0032 80E0      		ldi r24,lo8(Serial)
  61 0034 90E0      		ldi r25,hi8(Serial)
  62 0036 0E94 0000 		call _ZN5Print5printEii
  63               	.LVL5:
  64               	.LBE3:
  65               	.LBB4:
  66               		.loc 1 13 0
  67 003a 81E0      		ldi r24,lo8(1)
  68 003c 0E94 0000 		call analogRead
  69               	.LVL6:
  70               		.loc 1 14 0
  71 0040 61E0      		ldi r22,lo8(1)
  72 0042 892B      		or r24,r25
  73 0044 01F4      		brne .L4
  74 0046 60E0      		ldi r22,0
  75               	.L4:
  76               	.LVL7:
  77 0048 70E0      		ldi r23,0
  78               		.loc 1 15 0
  79 004a 4AE0      		ldi r20,lo8(10)
  80 004c 50E0      		ldi r21,0
  81 004e 80E0      		ldi r24,lo8(Serial)
  82 0050 90E0      		ldi r25,hi8(Serial)
  83 0052 0C94 0000 		jmp _ZN5Print5printEii

Очевидно, что нас интересуют только строки 4, 9 и 14 изначального скетча. Я позволил себе их вытащить и вставить в таблицу.

if (n != 0) n = 1;
n = (bool) n;
n = !! n;
   ldi r22,lo8(1)
   ldi r23,0
   or r24,r25
   brne .L2
   ldi r22,0
   ldi r23,0
.L2:
   ldi r22,lo8(1)
   or r24,r25
   brne .L3
   ldi r22,0
.L3:
   ldi r23,0
   ldi r22,lo8(1)
   or r24,r25
   brne .L4
   ldi r22,0
.L4:
   ldi r23,0

Нет замечаний по вытаскиванию?

А вот теперь изучаем. Видим, что варианты (bool)n и !!n - эквивалентны, что и следовало ожидать.

Что касается варианта с if, то он на два байта длинее. А по быстродействию, зависит от изначального значения n. При n != 0 он такой же, а вот при n==0 - он на 1 такт медленнее.

Убедились?

Теперь о "подложке". Когда я писал "дешевле не сделаете", я ничего не проверял и не исследовал, просто это нельзя сделать дешевле (в большинстве случаев, а не в искусственно созданном с volatile) из общих теоретических соображений об устройстве оптимизаторов. Поэтому, это верно практически для любого оптимизирующего компилятора. Если интересно, могу объяснить почему, но это серьёзный разговор с кучей "матана", боюсь, здесь неформат. Просто имейте в виду на будущее, Вы как разработчик может лучше меня знать как проектировать крупный проект, как управлять коллективом, как там ... не знаю, много чего, но в устройстве языков я узкий специалист и сравнивать мои знания и понимание языков со знаниями и пониманием у разработчиков (даже очень хороших) - это как сравнивать знания и понимание устройства автомобиля у проектировщика автомобилей и водителя (даже очень хорошего). Понимаете, о чём я?

Надеюсь, это не пойдёт на растопку холивара.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Ага ... я где-то читал, что volatile без нужды не стоит юзать, но что так сильно всё меняется ...

А вот, если забыть про эти споры, без них, как бы ты написал такую задачу? Повторяю, не "идеально-оптимально", а вот что первое в голову приходит тебе?

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

Я бы написал if(n) n = 1;

GarryC
Offline
Зарегистрирован: 08.08.2016

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

Да, я использовал char, чтобы упростить картину и оно действительно ни на что не влияет.
А вот volatile я использовал сознательно чтобы не погасить весь код оптимизатором.
Попробовал Ваш вариант на и вот что обнаружил - Вы таки правы.

И пусть меня лишат диплома, если я понимаю, почему при volatile int генерится

        ldd r24,Y+1
        ldd r25,Y+2
        sbiw r24,0
        breq .L3
        ldi r24,lo8(1)
        ldi r25,hi8(1)
        std Y+2,r25
        std Y+1,r24
.L3: 

и невыполняемый фрагмент просто обходится ветвлением, а для простого int получается

        ldi r24,lo8(1)
        ldi r25,hi8(1)
        cp r20,__zero_reg__
        cpc r21,__zero_reg__
        brne .L3
        ldi r24,lo8(0)
        ldi r25,hi8(0)
.L3:

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

Это что же - для того, чтобы компилятор делал правильный (ведь понятно, что второй вариант ассемблерного кода просто неправильный) код, надо все переменные делать volatile - фигня какая то.

 

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

Знаете, здесь очень продвинутый оптимизатор. Например, однажды я получил от него вот такое (правда, не помню, как ставились опции, кажется -Os)

Программа

// Вычисление факториала
inline long fact(const long n) {
	return n < 1 ? 1 : n * fact(n - 1);
}

void setup() {
  PORTB = fact(5);
}

void loop(void){}

Результат

setup:
	ldi r24,lo8(120)
	out 0x5,r24
	ret

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Думаеца, оптимизатор писали люди с IQ много больше чем даже 160.

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

Дело в том, что в общем виде такая задача (про рекурсивную функцию) неразрешима теоретически. Остаётся только предположить, что они просчитыват рекурсию на некоторую глубину и, если удалось - хорошо, а нет - генерят функцию.

Кстати, есть и другие не менее впечатляющие вещи, которые на самом деле проще и теретически там всё в порядке, но выглядит потрясающе. Например, некоторые оптимизаторы умеют делать такое:

static int f(const int a, const int b) {
     return a + b;
}
.................
int n;
........ 
int s = f(n, 3);
.........
return f(n+1, 3);
...........
n = f(analogRead(1), 3);

Так вот он сволочь рассуждает примерно так: ага, функция статик, значит из других файлов не вызывается. А в этом файле второй аргумент всегда 3. Сгенерю-ка я код 

static int f(const int a) {
     return a + 3;
}
.................
int n;
........ 
int s = f(n);
.........
return f(n+1);
...........
n = f(analogRead(1));

Ну, на самом деле он бы эту функцию просто выбросил, но я показываю то, что называется "частичными вычислениями".

Но здесь IQ уже не разработчиков компиляторов, а теоретиков. В частности, именно этот приём теоретически проработал В.Ф. Турчин - профессор МГУ и по совместительству писатель, дисидент - первый руководитель Московской «Международной амнистии», высланный из СССР и полжизни проработавший в США.

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

GarryC пишет:
- бред какой то.

Гарри! Не побрезгуйте советом.

Когда Вы убрали волатиль, оптимизатор работает с кодом, как он написан, именно в этом порядке.

Последовательные примеры преобразования, как у Вас в старом сообщении - не дадут нужной картины.

Посмотрите, как написал Евгений: он специально КАЖДЫЙ раз считывает переменную из analodRead(). И потом печатает ее.

Если просто написать три варианта подряд, оптимизатор будет в следующем учитывать предыдущий.

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

...

не надо съедать свой диплом, или что-Вы-там собирались с ним делать. Разработка программ и теория компиляторов - разные вещи. Нет обязанности точно знать принципы работы оптимизатора,

GarryC
Offline
Зарегистрирован: 08.08.2016

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

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

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

Знаете, здесь очень продвинутый оптимизатор. Например, однажды я получил от него вот такое (правда, не помню, как ставились опции, кажется -Os)

Программа

// Вычисление факториала
inline long fact(const long n) {
	return n < 1 ? 1 : n * fact(n - 1);
}

void setup() {
  PORTB = fact(5);
}

void loop(void){}

Результат

setup:
	ldi r24,lo8(120)
	out 0x5,r24
	ret

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

кстати это хороший пример на частичные вычисления.

Тут компилятор, по описанию и коду, точно и конкретно видит, что результат функции МОЖЕТ быть вычислен на этапе компиляции. Следом он решает вопрос о готовности потратить Х ресурсов на вычисление.

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

То есть подход такой (зная, что это задача этапа компиляции):

1. компилируем этот кусок.

2. запускаем в "песочнице".

3. немного ждем.

4. если есть результат - в оптимизатор его.

5. если нет результата или ошибка рантайма - код в генерацию - пусть автор сам разбирается. Ворнинг ему в диагностику.

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

GarryC пишет:

b707, Вы не ошиблись - при таком значении IQ функции чтения и написания едва ли могут быть осуществленны

Ну зачем мне врать? - какой IQ определился по тесту, такой и указываю :)

GarryC
Offline
Зарегистрирован: 08.08.2016

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