Как стать автором
Обновить

Целочисленная арифметика. Делим с округлением результата. Часть 1

Время на прочтение2 мин
Количество просмотров21K
Всего голосов 17: ↑9 и ↓8+1
Комментарии139

Комментарии 139

У вас деление заменяется на целую процедуру с дополнительным делением и умножением — а это ресурсоемкие операции.
Во всех языках есть команда деления с остатком, которая соответствует одной операции, возьмите остаток и сравните с делителем…
Пожалуйста, обратите внимание на комментарий, оставленный ниже.
Чтобы сравнивать остаток с делителем, их, во-первых, нужно сравнивать по модулю, а, во-вторых, потом как-то учесть их знаки.
Ну, и, в-третьих, результат сравнения не является числом, а логическим флагом, который в число нужно ещё превратить.
Операции умножения и деления технически реализованы как умножение и деление в столбик, как в школе учили (утрирую немного). Самая убийственная операция это деление. А сравнение это всего-навсего вычитание. Поэтому, иногда лучше сравнить несколько раз чем делить.
Флаг — это ноль или один это и нужно прибавить\вычесть к результату для округления.

ЗЫ: Я не раз встречал алгоритмы выглядящие прекрасно с математической точки зрения, но физическая реализация ужасна — как и тут.
Простите, но «флаг», то есть битовое/логическое значение, невозможно вычесть из числа или прибавить к нему.
Операция деления не самая убийственная — она по времени занимает столько же, сколько и операция умножения. А операция умножения, столько же, сколько в сумме операция обнуления регистра TEMP[2] и сложения. В случае того оборудования, с которым доводилось иметь дело мне, и которое не поддерживало арифметику с плавающей запятой, — 31мкс.
Да, вижу — архитектура рулит. В свою очередь, Вам предложу взглянуть на время выполнения таких команд у современных ПЛК Mitsubishi dl.mitsubishielectric.com/dl/fa/document/manual/plc_fx/jy997d16601/jy997d16601q.pdf стр930. Команда циклического сдвига вправо ROR, команда умножения MUL, деления — DIV. Третий столбец — 16 битные операции, четвертый 32-битные. Siemens такие данные на современные модели с некоторых пор упорно замалчивает, но по производительности пытается состязаться с Mitsubishi. Пройдя по этой ссылке есть шанс оценить возможность использования команд сдвига в разных старых моделях и время их выполнения в сравнении с умножением и делением dl.mitsubishielectric.com/dl/fa/document/manual/plc_fx/jy992d88101/jy992d88101e.pdf стр.378, наименования команд те же самые
Флаг является числом. Почему его нельзя вычитать и складывать с другими числами? Он какой-то особенный? Комплексный? Векторный? Всегда флаги использовали как числа, а числа как флаги.
Флаг — это битовое/логическое значение — «истина/ложь», складывать и вычитать бит с 16-ти или 32-битным числом нельзя. Эти операции выполняются только для чисел.

Если так раздражает деление, а операция сдвига не выполняется совсем или выполняется медленно, возможен иной алгоритм: (A+A+B)/(B+B). Этот алгоритм сразу на выходе даст округленный результат.
Я просто не могу понять, почему нельзя сделать так: 1+1010110001=1010110010.
Следовательно, получается формула ещё проще A/B+Остаток>4
Потому что устройство так не умеет делать, если единица представлена не 4-х, или 8-ми, или 16-ти, или 24-х, или 28-ми, или 32-битным числом, а единственным битом.
Формула, приведенная Вами, какая-то непонятная…
Почему бы не дописать нули спереди? Это любое устройство умеет делать.
Дописать-то, принципиально, можно. Только хлопотно это, и время.
Так Вы сперва поделитесь хотя бы соображением, как тот флаг сформировать и как учесть знаки чисел в числителе и знаменателе. Только после этого можно посчитать, что дольше, что быстрее. Само заполнение 7 бит по условию — 1,7мкс.
Я сейчас занят, но первое, что пришло в голову:
a/b=x'(огруг.) = x +(d*(x+1)-a<=a-b*x), где x — частное с отсечённым остатком.
Это где-то 6 действий, но тут надо по времени смотреть. Теперь мне кажется, что алгоритм из поста даже быстрее будет.
Благодарю.
Конечно. И тот, который расписал в дважды заминусованном посте habr.com/post/412613/#comment_18709951, состязается с ним по времени, потребляя при этом чуть меньше ячеек для промежуточных вычислений. Там одна команда деления, остальные команды — команды сложения
Заминусовали ваше отношение к флагам. Как вам такой алгоритм?
((A+A)/b+1)/2
4 операции, 1 ячейка памяти
Она знаки числителя и знаменателя не учитывает) И ячейка памяти никак не одна: числитель должен быть Double Integer, знаменатель, соответственно, Double Integer, результат первой операции деления 2хDouble Integer. Результат второй даст ещё +Double Integer
Я имел ввиду одну переменную. Но если так рассуждать, то в подпрограмму передаётся две ячейки integer с параметрами A и B. Тогда, используя всего одну буферную ячейку integer, можно выполнить все операции. Так что ячейка формально всего одна.

С учётом знака ставится аж 5 операций и один переход. Уже можно сравнивать производительность)
((A+A)/b+1 [if(sign1!=sign2) -2])/2
Ещё разок: одну никак не получится — у Вас числителе Double Int, поэтому знаменатель тоже Double Int, до деления результат тоже может оказаться Double Int, так что делить его на 2 придется в формате Double Int, что в итоге даст +4 ячейки к тем двум, куда были переданы входные значения…
А сравнение знаков в Cи смотрится классно)
Результат деления на b всегда будет int. Вы говорите, что процессор не поддерживает int2/int? В таком случае придётся задействовать ещё одну дополнительную ячейку, но не более. Единственное исключение — когда результат первого деления равен max или min. Но раз уж мы используем сразу две ячейки, то это вообще не играет роли. С другой стороны можно просто наложить ограничения.
Вы правы, верно, общее кол-во задействованных словных регистра — 4. Прошу прощения, это я затупил к ночи, зациклился на делении остатка, тогда как делить следует частное.
Тем не менее, алгоритм я бы несколько модифицировал:
1. Путем сложения удваиваем делимое.
2. Сверяем знаки делимого и делителя: если знаки не совпадают (исключающее или) вычитаем из делимого значение делителя, в противном случае, прибавляем его.
3. Путем сложения удваиваем делитель.
4. Выполняем деление.
Вуаля.
Куда дописать? на листе бумаги? Или к регистру статуса, где нужный флаг в результате сравнения находится в 7-м бите? Так сам флаг надо извлечь оттуда, и чаще всего единственный простой способ это сделать — выполнить условный переход.
В памяти меркеров это можно реализовать. Вопрос в другом, на кой это делать.
Потому что кто-то не умеет складывать числа разной длины.
Да почему ж) Тетраду с байтом легко
Для этой операции флаг надо превратить в число, а для этого нужна операция сравнения и присваивания. А тут уже сильно зависит от архитектуры, и на вычислительных архитектурах такие операции по времени выполнения могут поспорить с операциями умножения/деления и являются довольно затратными.
Там проблема, Alexeyslav, даже не в том, что озвученные Вами операции выполняются долго, а в том, что сравнивать значения остатка с делителем, как предлагал ultrinfaern, совершенно бессмысленно: остаток по абсолютной величине всегда меньше делителя, к тому же остаток с делителем могут быть одного знака, а могут быть разных. Операция сложения остатка с самим собой вкупе с операцией деления решают вопрос и с величиной прибавки и с её знаком.
Так флаг это и есть число. Это числа для удобства превращают во флаги.
Уже говорил, что флаг это бит. Его не из чисел выдергивают, а формируют логической операцией.
Логическая операция, это тоже арифметика и с физической, и с математической точки зрения. Так операция сравнения это (b-a)/|b-a|. В физике, например, компаратор действует аналогично. На самом деле, все операции компьютер осуществляет арифметикой. Как никак в цифровом веке живём.
То компьютер. У этого «железа», как уже не раз говорил, нет операции взятия абсолютных величин.
Плюс у Вас операция деления, супротив которой все протестуют.
Операция модуля выполняется обнулением знакового бита. А протестуют тут не против деления, а против его многократного использования в вашем алгоритме. Но это опять же надо смотреть по производительности.
p.s. я вам выше написал свой алгоритм в 4 операции и 1 ячейку памяти.
Это да, можно, командой WAND…
Команд деления у меня только две. Первый шум начался из-за команды умножения. Я ей заменил две команды — обнуления старшего слова и сложения — в моей технике суммарно они выполняются столько же времени, сколько одна команда умножения.
Господа минусующие! Нижайшая просьба комментировать, что именно в опубликованном вызывает ваше здоровое недовольство.

Не минусовал, но всю жизнь писал, как yizraor, ваш вариант даже в кошмарном сне бы не приснился: вторая операция деления вместо сдвига — это ужасно.
На Си это просто
result = (x + (y>>1)/2) / y
или даже
result = (x + y/2)/y


Операция сдвига практически бесплатна в отличие от деления.

Но речь то идет не о ПК, а о ПЛК и микроконтроллерах, об их вычислительных возможностях. Во-первых, это «железо» Си напрямую не потребляет — то, что написано на Си, компилируется в язык тех команд, которые это железо поддерживает. А оно, вследствие особенностей архитектуры, может: а) совсем не поддерживать сдвиговые операции; б) поддерживать только операции циклического сдвига; в) поддерживать оба типа операций сдвига. Однако и во-втором, и в-третьем случаях, операция сдвига занимает времени существенно больше, чем сложение, умножение, деление. Например, у самого современного ПЛК время на выполнение операции циклического сдвига, как минимум, вдвое превышает время на выполнение операции деления сдвоенных целых чисел.
Мне тут другой алгоритм пиарили, так время его выполнения на 20 с лишним процентов выше, чем описанного мной в публикации.
Если программируете ПЛК или микроконтроллеры, то у меня к Вам вопрос: всегда ли анализируете скомпилированный код и оцениваете время выполнения написанной процедуры?
Так Вы бы в статье прямо и написали, что речь идет о ПЛК, никто бы с Вами и не спорил — в АСУТП вечно все не как у людей. А то я, например, особенно глядя на Ваш ник, подумал что мне сейчас будет открыто нечто сокровенное, а тут ПЛК.
ПЛК и микроконтроллерах
Кстати, а что Вы понимаете под словом микроконтроллер? Полагаю, что большинство здесь присутствующих под этом термином подразумевают однокристалку, а Вы?
Во-первых, это «железо» Си напрямую не потребляет — то, что написано на Си, компилируется в язык тех команд, которые это железо поддерживает.
Никакое железо Си напрямую не «потребляет», так же, как и другие языки программирования, а исполняет программу в машинных кодах. Впрочем, подозреваю, что то «железо», с которым Вы работаете, вовсе не железо, а некая программная система, выполняющая Ваш код, и ее система команд к системе команд того, действительно «железного» процессора, на котором все это крутится, не имеет ни какого отношения. Если я не прав в своих подозрениях, то поправьте меня, но я не представляю себе архитектуру процессора, выполняющего сдвиг дольше умножения и, тем более, деления.
Кстати, а что Вы понимаете под словом микроконтроллер? Полагаю, что большинство здесь присутствующих под этом термином подразумевают однокристалку, а Вы?

И я про них же)
Если я не прав в своих подозрениях, то поправьте меня

Поправлю) Об архитектуре АЛУ процессора ПЛК я говорил в комментариях предыдущей своей заметке: «Анализ бита под «результирующие битовые операции» со словами не подпадает, как и операции модифицирующие значение отдельного бита. Под «результирующими битовыми» мной имелись в виду именно операции побитового сдвига слова, так как операции с отдельно взятыми битами выполняются в битовом аккумуляторе — стеке логических операций, а операции со словами уже в другом аккумуляторе, с пословной организацией.»
Когда-то давно процессор ПЛК имел АЛУ только с битовым аккумулятором, и вот тогда все операции со словами выполнялись очень медленно, команды умножения/деления в особенности.
В статье Вы пишете не об «архитектуре АЛУ процессора ПЛК», а об архитектуре того, что Вам, как АСУТПшнику, предоставили разработчики ПЛК Mitsubishi моделей FX3S/3G. Чтобы говорить аб архитектуре процессора, для начала нужно посмотреть документацию именно микропроцессора, на которой выполнен данный ПЛК.
Те модели, корпуса которых вскрывались, выполнены на каких-то заказных PGA, никакой документации на которые нет. Обозначение никак не пробивается. Производитель на корпусе тоже не указан.
Тогда, наверное, архитектуру собственно процессора и не зачем обсуждать, можно говорить только о ПЛК, как «вещи в себе», но при этом четко обозначать, о чем идет речь.
Не совсем. С самой архитектурой АЛУ таких устройств я знаком из документации и практики. А вот что за кристалл, какова тактовая частота и MIPS, вот эта информация сохраняется в тайне.
А Вы уверены, что то, что Вам предоставляют средства разработки и документация на ПЛК и есть физическая реализация, а не программная эмуляция системой исполнения некоего виртуального процессора? Если честно, то с Mitsubishi сталкиваться не приходилось, но приходилось с ПЛК Сименс — там именно так и сделано и физический процессор Infenion, на котором реализован контроллер не имеет ничего общего с архитектурой, представляемой системой разработки.
Уверен. Сам когда-то писал операционки под МК. Программист видит исполняемый макрокод. Он состоит из коротких инструкций известной длины. При считывании этот код идентичен тому, что был загружен в ПЛК. Если бы была «прослойка», трансформирующая написанную программу в иную систему команд, средство разработки не смогло бы восстановить оригинал. Тут полная корреляция с объемом кода. Преобразование только в отношении ST (Паскаль-подобного/Си-подобного языка) справедливо. Написанное в других IEC-языках, особенно в Melsec IL, «как слышится, так и пишется».
Если бы была «прослойка», трансформирующая написанную программу в иную систему команд, средство разработки не смогло бы восстановить оригинал.
Почему? Вы пишете на некоем «ассемблере» (в Сименсе — это STL, в большинстве других ПЛК — это IL, суть одна и та же), дальше Ваша программа транслируется в исполняемый байт-код, который Вы и загружаете в ПЛК. Но это исполняемый код для исполняющей системы, а не машинный код процессора. Именно из этого бай-кода средство разработки и восстанавливает оригинал. Как некий аналог, можно привести в пример исполняющую систему Java, там Вы тоже можете получить некое подобие ассемблера, описывающего исполняемый байт-код и даже восстановить из него исходный текст, но этот ассемблер не имеет ничего общего с системой команд реальной «железной» машины, на которой выполняется.
Всё верно. Но языковое представление этого массива чисел — ассемблера ПЛК- есть Макроассемблер, и они напрямую, а не косвенно взаимосвязаны друг с другом. Тогда как из кода, полученного в результате компиляции программы, написанной на Си, уже никогда не получить чего-либо хоть отдаленно напоминающего исходник.
А я, например, могу представить… особенно если это архитектура заточенная на ускорение вычислений, и операции сдвига там не в приоритете. Например, если умножение/деление выполняется за 1 маш.цикл(а чаще и вовсе по 8 чисел за раз), а сдвиг за два т.к. КОП слишком длинный.
Команды сдвига в таких устройствах попросту утрачивают актуальность для программиста, поскольку имеется битовая память, где операция побитового сдвига принципиально может быть заменена операцией пересылки группы бит, выполняемой примерно за 500нс, на сколько бы бит не понадобилось сдвигать слово.
Ну видимо все таки не утрачивают, раз приходится два раза делить для простого округления.
Поправка: собственно для округления приходится делить однократно. Сдвиг можно организовать в памяти меркеров. Но сам сдвиг, в данном случае, не так прост. Если сдвигать «вправо», вдвое уменьшая значение делителя, возникают ситуации, когда будем округлять в большую сторону, даже когда по правилам арифметики следует округлять в меньшую. Если сдвигать «влево» вдвое наращивая значения остатка. то необходимо контролировать флаг переполнения и старший бит числа, таким образом обеспечив переход к двойному целому и перенос знака или его сохранение на месте. Сохранение знака числа также требуется и при сдвиге «вправо».
Теоретически, такое представить можно, но лучше бы привести ссылку на документацию подобного процессора или, хотя бы, его тип.
Потому говорить о реализации в общем случае не имеет смысла, а имеет смысл говорить о реализации для чипа A1234, потому как в A1235 может быть оптимизация и сдвиг будет быстрым, от чего реализация через деление будет страшным тормозом.
PS. Никакое железо Си напрямую не потребляет, потребляется машинный код, а уж во что Си[++] будет транслирован — зависит от компилятора и его флагов. Иногда они «умные», иногда не очень — когда нужна скорость приходится смотреть на результат и пробовать разные варианты.
Согласен и в том, и в этом.
Вот я и не пользуюсь Си, чтоб результат не зависел от таланта или его отсутствия у разработчика компилятора, а пишу как можно ближе к железу, дабы достичь минимального времени выполнения программных процедур.
Но речь в публикации, собственно, не об этом, т.е. не о времени и не о конкретном способе округления, а о том, что, то об округлении позабудут, то об ограничениях, накладываемых размерностью чисел. А куском, акцент действительно получился на втором.
Современный компилятор иногда справляется лучше человека, особенно на больших объёмах кода, когда каждый цикл тюнить дорого. Но посмотреть узкие места и мочь их переписать завсегда полезно. Как и про переполнение (об этом вообще редко помнят).
В частности, об этом, о переполнении, я и хотел поведать дальше. Но, видимо, сперва придется откорректировать этот текст. Во всяком случае, изъяв из него описание алгоритма, который всех раздражает больше всего тем, что в нем присутствует вторая команда деления. Хотя я проанализировал, и часть альтернативных алгоритмов, озвученных мне в комментариях, дают либо в корне неверный результат (при разнознаковых значениях числителя со знаменателем), либо ошибку округления…

"О микроконтроллерах" — операция сдвига примерно всегда есть:


  • AVR: LSR для 8-битных беззнаковых, ASR для знаковых, для чисел 16+ бит — ROR для всех байтов кроме старшего, итого 1 однотактовая операция на байт
  • ARM — то же самое для 32-битных
  • 8051 — RRC; PIC — LSRF/ASRF/RRF
  • MSP430 — RRA/RRC

Деление может вообще отсутствовать (AVR) или требовать больше тактов (Cortex M3 — от 2 до 12, и это ещё дёшево!)


Деление — сложная и дорогая операция, его все стараются заменить умножением или вообще сдвигами. Поэтому за лишнее деление вас заминусуют на автомате, и вам надо очень чётко объяснить, почему именно для вашего случая деление выгоднее.


Что касается ПЛК — с ними не работал. Вероятно, там есть свои особенности (как я понимаю, прямого доступа к МК нет, всё довольно медленно и на фоне этого теряется разница между делением и сдвигом, если он есть — так?). Вот если бы вы акцентировались на специфике конкретного ПЛК (ну там, разработчики ПЛК сдвиг не дали) — другое дело. Но даже если нет операции сдвига — не вижу проблемы использовать стандартный алгоритм (прибавить половину делителя перед операцией), будет два деления, как и у вас. Разве что операций перемещения может оказаться больше, но это опять же случай, когда надо разобрать и показать, почему надо использовать ваш алгоритм вместо стандартного.

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

Да, это, безусловно, так.
А я в своём первом комменте пытался объяснить, за что могут рефлекторно минусовать. Сам был шокирован, но не настолько, чтобы минусовать (даже если бы была возможность) — скорее объяснить, как обычно делают и почему.


Да, возвращаясь к вопросу "всегда ли анализируете скомпилированный код и оцениваете время выполнения написанной процедуры" — только "узкие места". Нет смысла оптимизировать всё.
А делений избегаю рефлекторно. Привычка ещё с 8080.

Понятно) У меня вот старые привычки постирались, какое железо со своим набором команд, такой и код. Всегда считаю его длину и почти всегда время выполнения. Потому как любимое занятие — написание драйверов и компактных программных процедур, которые могут быть использованы другими программистами.
По поводу минусования… — как думаете, за что вот этот мой комментарий ажно дважды отминусовали habr.com/post/412613/#comment_18709951?
> Деление — сложная и дорогая операция, его все стараются заменить умножением или вообще сдвигами. Поэтому за лишнее деление вас заминусуют на автомате, и вам надо очень чётко объяснить, почему именно для вашего случая деление выгоднее.

Судя по приводимым таблицам, где умножение и деление имеют равные времена по 450 нс — деление там выполняется каким-то хитрым встроенным блоком, который работает отдельно от основной логики и по характеристикам сходен с высокоуровневым процессором.
Иначе я этот феномен объяснить не могу — потому что для современного компьютерного дела открытие однотактного деления 32/32 бита это что-то на уровне доказательства Большой теоремы Ферма.
Но тогда непонятно, накойхер там вообще логика этого ПЛК, если есть хороший процессор…

Интерпретатор же. ПЛК нужно не быстродействие, а простота и надёжность.

Умножение и деление 32-битных чисел не по 450нс, поболее — 3,4 и 3,7мкс соответственно. Вот логические операции, которые для ПЛК являются базовыми, поскольку его задача управление процессами, в т.ч. реализация релейно-контакторной логики, занимают 210нс.
Почему процессор так быстро считает, предположить можно — он, скорее-всего, на ПЛМ реализован, т.е. операции поразрядного сложения и вычитания со сдвигом заведомо аппаратно реализованы на вентилях. Остается выдернуть операнды из памяти в процессор, активировать соответствующую цепочку логических элементов, и результат записать обратно в память. То есть основное время занимает загрузка-выгрузка из памяти. Это хорошо объясняет то обстоятельство, что время выполнения команд с 32-битными операндами мало отличается от 16-битных.
Мало отличается, скорей всего, потому что там реализована только команда 32-битного деления, а 16-битные числа просто расширяются до 32-битных и используется одна процедура.
Относительно 32-битного, логично.
Но если внутри всё равно есть процессор?

Ну и что? Если напрямую звать его команды нельзя?
В калькуляторе тоже внутри есть процессор, но команды напрямую не позвать. О кофеварке или автомобиле я вообще молчу (хм… а сколько процессоров в автомобиле?)

> Ну и что? Если напрямую звать его команды нельзя?

То, что это уже никак не «простота и надёжность», ради которой отказываются от процессора.
Даже если он всего лишь выполняет умножение и деление, это серьёзный модуль внутри.
И тогда возникает вопрос, а зачем вокруг делать обвязку, которая убивает 99% возможностей процессора.
Именно в этом и заключается надёжность — вы не можете вызвать команды напрямую которые позволят «выстрелить в ногу».

Представьте себе обычный микроконтроллер (процессор с встроенной памятью, удобными GPIO ногами и небольшой кучкой периферии). Можно дать юзеру возможность напрямую управлять им через ассемблерный код — но, к примеру, это даст ему возможность подать +5V на ногу, которая в данный момент подключена к земле. Или написать бесконечный цикл и подвесить проц (не факт, что юзер сделает правильную настройку watchdog).
А можно — ограничить его, дав лишь очень урезанный набор команд, после каждой команды отслеживать состояние системы и т.п. — не давая ему написать и выполнить опасный код, и упрощая написание (за счёт урезания возможностей).


Как думаете, что безопаснее?


Простота и надёжность — не простота процессорного модуля, а простота написания кода (и вытекающая из этого бОльная надёжность кода). И во многих задачах "убить 99% возможностей" — окупается.

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

У них просто своя специфика: с одной стороны, программы проще, с другой — за баги больнее наказывают (повисший Ворд просто перезапускается; повисшая котельная зимой даст замёрзнуть трубам)

Относительно простоты задач Вы категорически не правы. Задачи бывают ох какие объемные (управление производственными линиями и цехами) и ох какие сложные, с кучей алгоритмов, при том реализуются они на совсем небольших контроллерах, поскольку внешних сигналов-то немного, зато режимы работы установки и различные алгоритмы работы по своему числу и сложности реализации подчас требуют напряженного многомесячного труда многоопытного программиста.
за баги больнее наказывают
Отличный повод использовать платформы, под которые можно писать только на Ассемблере.
Почему бы не исправить статью и не написать что она для ПЛК, о существовании которых 90% прочитавших статью даже не знают, не говоря уж об особенностях их вычислительных возможностей?
Да, уже подумываю над… Тем более, что акцент статьи задумывалось сделать отнюдь не на ПЛК и его выч.возможностях, а совсем на другом. Но почти все видят только это.
Если бы акцент был бы на собственно ошибках и методах их исправлений, то не стоило давать такой крайне специфичный пример который для большинства знакомых читателям архитектур не является оптимальным. Сначала надо решить что важнее.
Важнее первое.

Автор, Вы пишете: "… округление результата до ближайшего целого организовать элементарно. Для этого достаточно удвоить остаток деления, просуммировав его сам с собою, а затем вновь поделить его на то же число..."


Прошу простить, но считаю Ваш вариант неэффективным способом.
Я в своё время придумал другой: прибавить к числу половину делителя, затем выполнить само целочисленное деление.
Если делим в цикле на одно и то же число, то половину делителя можно вычислить один раз. В противном же случае: целочисленное деление пополам — это битовый сдвиг на 1 позицию вправо, что тоже очень быстрая операция :)
Под работу с отрицательными числами данный способ расширяется без особого труда: добавится условный переход, но это лучше чем второе деление.


Пример для дроби 64/13:
(64 + (13 / 2)) / 13 = (64 + (13 >> 1)) / 13 = (64 + 6) / 13 = 70 / 13 = 5

Благодарю. Ваш способ понятен, но его реализация в условиях расчета в ПЛК и ряде микроконтроллеров, неудачна. Во-первых, операции сдвига в таких устройствах, вследствие определенной организации АЛУ, или выполняются дольше операций сложения, деления, умножения, а кое-где и вовсе не поддерживаются (об этом я писал в комментариях к предыдущей своей заметке). Во-вторых, это предложенный Вами способ также завязан на деление, результат которого нужно хранить, а делить (помимо процедуры округления нужно единожды). В-третьих, предложенный Вами расчет явно оперирует с абсолютными величинами (по модулю) — контроллер не поддерживает операций взятия абсолютной величины. Ну и, в-четвертых, в продолжении изложения материала, я планировал показать, какие встречаются задачи и как они реализуются. Из этого материала, в частности, должно проясниться, с какими вычислениями приходится оперировать, в том числе экономя ресурсы, которые у контроллеров, в отличии от компьютеров, весьма ограничены.
Код кажется длиннее лишь потому. что реализован в формате подпрограммы, которую можно вызвать сколь угодно раз.
А что это за архитектура такая, в которой есть сложение/умножение, и нет побитового сдвига? Что-то не верится, что такие жертвы в принципе могут быть оправданы (для умножения по логике должен поддерживаться хоть какой-то сдвиг). Вам на самом деле приходится применять этих зверей на практике?
Скажем так, приходилось. Например, ПЛК Mitsubishi серий FX1S и FX1N, которые до сих пор в ходу, ибо служат десятилетиями. Новые модели уже поддерживают и сдвиги (частично) и вычисления с плавающей запятой, но все эти операции выполняются гораздо дольше целочисленных операций со словами. В комментариях к предыдущей статье немного пояснял, почему.
Отсутствие поддержки операций сдвига не самое ужасное. Как-то пришлось решать задачу с вычислениями на контроллере, который умножать два 16-битных числа умел, а поделить результат умножения — нет, и его пришлось такой арифметике программным способом обучать.

Так и пишите, что так мол и так — столкнулся с экзотикой, на которой сдвиг дороже деления 8-O (на этом месте вы уже привлекли внимание аудитории), поэтому вместо общепринятой реализации округления сделаем такой костыль.

Простите моё невежество, а какая есть общепринятая?
Что касается экзотики, то никакой экзотики нет. Это норма для такого железа, когда время выполнения операции сдвига вдвое превышает время операции деления сдвоенных целых чисел.
К слову, даже алгоритм, о котором говорит yizraor, с меньшим числом операций деления, отнимает по времени на 20 с лишним процентов больше, чем тот, который озвучил в публикации.
Вы, конечно, извините, но подавляющее большинство читателей Хабра живет в мире, где время выполнения операции сдвига никак не может превышать время операции деления.
Спасибо, учем-с) Они еще и живут в мире, где сама операция сдвига реализована в процессоре;)
Загуглил ПЛК Mitsubishi, средняя найденная мною цена — примерно $70. Почему бы не перейти на МК, которые и по цене намного дешевле, и по возможностям намного круче?
70USD это не цена ПЛК, столько разве что модули ввода-вывода к нему стоят. ПЛК разрабатываются и изготавливаются специально для промышленных применений, даже полуготовые игрушки типа Ардуин и Рапсберри в промышленности не годятся. Это раз. Два — они как модульный конструктор, специально заточенный для решения определенного класса задач. Если что-то внезапно вышло из строя, быстро снял модуль и поменял.
полуготовые игрушки типа Ардуин и Рапсберри в промышленности не годятся
Согласен, но как на счет МК типа STM, например? Они вроде тоже в промышленности применяются.
они как модульный конструктор
А зачем совмещено конструирование и программирование? Если идет ориентация на программирование — можно ведь запросто реализовать в железе все элементарные операции, это доказано на практике. Если на конструирование — берите да собирайте схемы из захардкоженных логических элементов, зачем в них еще что-то дописывать? Я что-то не так понимаю?
Во-первых, процессоры STM не сам по себе живут, им нужна печатная плата и внешняя обвязка. Нужны УСО с опторазвязкой и т.д. Для крупного производства вопрос цены не столь критичен. Критично другое — надежность.
Ни о каком конструировании при сборке ПЛК речь не идет — просто его конфигурация «нанизывается» из модулей — базового, с процессором внутри, и модулей расширения. Есть и другой конструктив — на шасси. Гибкость, универсальность и быстрый ремонт модульной заменой, вот что ставится во главу угла.
Те кто переходит от разработки электронных схем, печатных плат и Embedded Soft к микроконтроллерам, очень быстро ощущают разницу в скорости разработки, в суммарных затратах на разработку решения и эту самую гибкость в пользу ПЛК, после чего обычно напрочь отказываются от разработок и создания электроники под конкретную задачу.
С первым абзацем трудно не согласиться, а вот во втором Вы опять путаете понятие «микроконтроллер», как его понимают большинство здесь присутствующих, и ПЛК. STM — это и есть микроконтроллер, а то, с чем работаете Вы — ПЛК. Насчет скорости разработки именно программной части — можно поспорить. Выше Вы сами пишете, что не можете доверять компилятору C и вынуждены писать не ассемблере, а большая часть софта для однокристалок сейчас благополучно пишутся именно на C и даже на C++ (если хорошо понимать, что можно, а чего не стоит делать). На ассемблер приходится спускаться довольно редко, только когда это действительно необходимо. Именно поэтому Ваши проблемы со сдвигом и подобными операциями, выполняющимися на микроконтроллере за 1 такт (для того же STM — это, в зависимости от тактовой частоты, порядка десятков наносекунд) большинству непонятны.
Я ничего не путаю) Для ПЛК тоже можно писать программы на Си-подобном языке, только код будет неоптимален и совсем не похож на код исходника. Скорость разработки программы зависит больше не от того, на чем написано, а от того, кто пишет. Когда сказал о скорости разработки, само собой. имел в виду скорость разработки решения в целом, от и до, а не только его программной части.
То, что «многим непонятно», уже отметил для себя.
Для ПЛК тоже можно писать программы на Си-подобном языке, только код будет неоптимален и совсем не похож на код исходника.
ключевое слово — на Си-подобном.
Скорость разработки программы зависит больше не от того, на чем написано, а от того, кто пишет.
Естественно, если человек не умеет программировать, то никакой язык высокого уровня ему не поможет. По поводу того, что уровень языка имеет мало значения — Ваш тезис опровергается всей историей развития программирования. Кстати, тот же C, ранее считавшийся языком высокого уровня, с некоторых пор перестал считаться таковым. Но в области микроконтроллеров для C пока нет полноценной замены (да, про Rust знаю, но он еще слишком молод для повсеместного использования).
Я согласен с тем, что писать на Си для МК намного удобнее, чем покомандно кодить. Сам во времена, когда ещё персоналки были только отечественными и строго под замком, писал длинный код в несколько кБ на листочке в клеточку, прокручивая работу программы в голове.
Но вот в части разработки программ для ПЛК с начала 2000-х Си фактически укокошил профессию программиста систем автоматики и продолжает добивать средства разработки программ для ПЛК, из которых стараниями нерадивых и необразованных менеджеров, которые слыхом не слыхивали о сквозной программной совместимости. стали изымать прочие языки, входящие в стандарт IEC. Написанные прежде программы обновленными версиями софта больше не открываются, а годами наработанные библиотеки готовых элементов и процедур вмиг превратились в труху. Просмотр целиком скомпилированного программного кода, написанного на языках, отличных от Си, больше невозможен — только мелкими кусочками и т.д., и т.п.
Когда в начале 2000-х с Запада надуло поветрием брать на работу Си-программистов взамен программистов ПЛК, а вместо самих ПЛК ставить ПК с силиконовым диском, вторая категория работников вынуждена была оставить свой привычный труд… Чуть позже у сишников, трудящихся в иных сферах, выросли зарплаты и новоявленные программисты систем автоматики хлынули туда, где больше платят, ПК с силиконовыми дисками, не прослужив и двух лет стали резко сыпаться, решили вернуться к старым, добрым ПЛК, а программистов-то, настоящих, знающих линейку с которой нужно работать, уже ищи свищи. Тогда и пришлось приделывать примочку к пакетам разработки в виде компилятора с языка Си. Теперь программистов на Си пруд-пруди, а заработки в профессии сильно упали.
Складывается такое ощущение, что мы с Вами живем в разных параллельных вселенных, так как наблюдаемое нами развитие истории если и не строго противоположно, то хотя бы ортогонально.
Теперь программистов на Си пруд-пруди
Знание языка C для программиста сродни знанию латыни для врача. Но от этого не стоит считать любого программиста, знакомого с этим языком, а их действительно — большинство, именно C программистами, коих сейчас не так и много на фоне всех других языков.
Рассказываю о том, чему был непосредственным свидетелем. А вот во втором моменте я именно это имел в виду, владение Си, как латынью, а не то, что они именно СИшными программистами трудятся.
Как говорится: в каждой избушке — свой погремушки. Естественно, работая в разных конторах, у нас складывается разное видение истории смены тенденций.
код будет неоптимален
Это говорит о том, что в 2018 году для обсуждаемой архитектуры еще нет нормального C-компилятора — еще одна причина оставить эту архитектуру в прошлом.
и совсем не похож на код исходника
Про это не очень понял. Он ведь и не должен быть похожим, то С, а то Ассемблер.
Скорость разработки программы зависит больше не от того, на чем написано, а от того, кто пишет.
Если Вы способны писать качественный код на Ассемблере с той же скоростью, что и на С, то мне остается только Вас поздравить. Но мне все же кажется, что большинство людей в мире не такие.
Тогда порадуйтесь, я способен;)
Точно способны? На архитектурах, знакомых мне, учесть все нюансы, которые способны увеличить эффективность программы, практически невозможно.
Уверен, что да (только сперва надо Си выучить;). О каких архитектурах речь?
Ну, например, x86-64, ARM. На них кодить на Асме нужно как минимум очень осторожно.
Занимательно) Я почему-то полагал, что на Ассемблере x86-64 пишут уже только биосовцы и создатели особо изощренных вирусов.
Как раз потому, что слишком опасно. Это имеет смысл только если нужны команды процессора, невыразимые в С. Поэтому ИМХО Ваша уверенность в своих ассемблерных силах не всяким будет воспринята всерьез.
:) Фактически, а не на словах доказать, насколько ты хороший программист, можно лишь на практике. За прожитые годы вынужден был проделывать это неоднократно. Как по мне, на словах должно быть достаточно одного примера — разработка операционки для стенда обучения программированию на однокристалке. Объем программы примерно 2k, зашиваемая в EPROM, средствами разработки которой выступили исключительно голова, ручка и тетрадные листочки в клеточку. Код писался, прокручивался и отлаживался в голове, а на листки записывался сразу начисто и сразу рабочим.
Цикл записи в EPROM этому способствовал, лишний раз обнаружить баги до записи. А когда заменяешь это дело на RAM для ускорения цикла написание-прошивка-тестирование то проблема только обострялась… чуть что не так — программа затирает сама себя и вводи всё заново.
Это у кого как получается, и у кого какой бэкграунд.
гибкость в пользу ПЛК
Отсутствие операции побитового сдвига — это гибкость?
Я ж не об этом. Я о том, что новая задача может быть решена на том же железе.
А еще ее наверняка на вакуумных лампах можно решить. Но от этого ведь совсем не легче?
Ох, не любите Вы ПЛК)))
Можно я отвечу за picul? Я их ненавижу, так как по ряду сложившихся обстоятельств, уже имея солидный опыт разработки больших проектов на C++, а так же некоторый опыт эмбединга, вынужден был 4 года программировать ПЛК Сименс. Эти годы я считаю бессмысленно потерянными из своей жизни программиста.
У меня их выпало нааамного больше. Причем, Сименс когда-то я тоже программировал. И был момент, когда в качестве программиста ПЛК Сименс все АСУТПшные компании города, делавшие проекты на их контроллерах, рвались «приобрести» меня за любые деньги, на любых условиях. Но я уже более полугода как перешел работать с ПЛК Митсу, которая профукала рынок.
Я же и не пытаюсь сравнивать свой опыт в области ПЛК с Вашим. Я честно говорю, что весь этот период работы считаю бесполезно потерянным временем. Причина — именно то, чему Вы посвятили обе свои статьи: вместо решения действительно актуальных проблем находишься в перманентном состоянии войны с несовершенством системы разработки. Причем, для большинства АСУТПшников, не имеющих серьезного опыта работы с «нормальными» средствами разработки, это является нормой. Естественно, как только смог посчитать возможным прекратить эту деятельность, я ее прекратил и вернулся к более привычному для себя программированию «традиционными» средствами.
Так в ПЛК по сути и стоит свой МК с микропрограммой. Но дело тут не в МК, а в том что для ПЛК все интерфейсы стандартизированы и имеют защиты от статики, перегрузки, гальваническую развязку и прочее. Как начнёшь аналогичное разрабатывать на основе МК с теми же характеристиками и требованиями, сразу же с первых шагов перебъёшь этот ценник. И во вторых насобираешь детских багов в процессе разработки прошивки, гуляя по граблям.
Все правильно, но вот извращения, связанные с обходом ущербности доступных элементарных операций, минимизации багов никак не способствуют.
Все баги появляются тогда, когда между мной, разработчиком прикладных программ для ПЛК и самим ПЛК встает другой человек, допиливающий средство разработки, — с собственным видением, как организовать компиляцию, или как сделать графические элементы, допускающий кучу ошибок и затыкающий их очередными патчами. И обходить внедренные ими баги не в пример сложнее, чем приспособиться к вычислительным возможностям железа.
Да, во всем виноват компилятор)
Я на полном серьёзе… Причем, в новых версиях ПО меня вдобавок лишили возможностей их обходить
Просто обычно слова «баг компилятора» используются как шутка над неопытным программистом. Если же это не шутка, то, как я уже писал выше, отсутствие нормального компилятора С для обсуждаемой архитектуры, на мой взгляд, является весомой причиной полагать, что архитектура сильно устарела.
Это не архитектура устарела, это программисты измельчали…
Правда? Просто у нас на x86-64 баги компилятора встечаются ну очень редко.
С учетом, что в другом своем комментарии сказали об ассемблере x86-64, то это вполне логично звучит.
Если у меня листинг программы самописный, составленный непосредственно из инструкций ПЛК, то в этом случае вообще никаких багов. Баги появляются тогда, когда программа составляется в IEC IL, или графических Ladder Logic/FBD, вот тогда компиляция уже зависит от фантазий разработчика пакета программирования. Если же она написана на языке высокого уровня (ST), то тут вообще широкое поле для фантазии — коду после компиляции можно удивляться бесконечно.
то в этом случае вообще никаких багов
Ну это да, если, конечно, не считать тех, что вы сами создали.
коду после компиляции можно удивляться бесконечно
Если так, почему никто не взял да не написал нормальный пакет программирования?
Ну это да, если, конечно, не считать тех, что вы сами создали.

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

А кто это должен делать? Сами программисты ПЛК?

Лет 7-8 назад был пакет программирования с малым количеством изъянов. От него сперва отказались, заменив другим, намного более убогим, выход которого анонсировали в течение лет эдак 10-ти (анонсировали, конечно, не убогий, а передовой). А через некоторое время из этого убогого ещё и изъяли все текстовые языки, кроме ST. И новые контроллеры программируются только новым софтом. Все персональные, годами наработанные библиотеки и старые программы, написанные текстом, в нем больше не открываются. Так что имеем то, что имеем.
Сам я сразу пишу работающий код.
ОК))
А кто это должен делать?
Ну, наверное Вы, раз умеете сразу работающий код писать)
От него сперва отказались, заменив другим, намного более убогим
Зачем?
А через некоторое время из этого убогого ещё и изъяли все текстовые языки, кроме ST.
Ну так не обновляйте ПО.
Все персональные, годами наработанные библиотеки и старые программы, написанные текстом, в нем больше не открываются.
Если это текст, то его открыть можно любым блокнотом. Или компилировать нечем?
А кто это должен делать?
Ну, наверное Вы, раз умеете сразу работающий код писать)

) Так в настоящее время я ж прикладной программист, программист ПЛК, а не разработчик IDE на языках верхнего уровня
От него сперва отказались, заменив другим, намного более убогим
Зачем?

Насколько знаю, тупоголовыми менеджерами двигали две вещи: 1) мечтали объединить два софта (один предпочитали и использовали в Азии, другой в Европе) в единый пакет, в итоге же, получили не единый пакет, а три раздельных; 2) старый пакет разрабатывался партнером, с которым, как и с другими многолетними партнерами, новый менеджмент корпорации сумел рассориться…
А через некоторое время из этого убогого ещё и изъяли все текстовые языки, кроме ST.
Ну так не обновляйте ПО.

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

В новом компилировать нечем. Ни программные куски, ни библиотеки, написанные текстом, в программу, созданную в этом пакете даже не добавить.
Ну и сложно у Вас все… Но это, конечно же, не повод переходить на современные платформы.
Вы не так понимаете. Это очень современные платформы, только специализированные. Другое дело, что сам бы с удовольствием поменял эти современные платформы, на совсем другие современные.
Вы знаете, в области АСУТП в этой шутке есть приличная доля истины. Только, я бы заменил слово «компилятор» на более широкое понятие «средство разработки».
Почему? Под компиляцией мной имелась в виду именно компиляция, а под средством разработки именно средство разработки.
Я отвечал не Вам, а на комментарий
Да, во всем виноват компилятор)
А под средствами разработки, помимо собственно компилятора, я подразумеваю и сами языки программирования, и все прочее, что объединяет IDE.
Понятно. Просто если в средстве разработки писать непосредственно на языке команд контроллера, то там командная последовательность банально транслируется в код безо всяких ошибок.

Понял Вас.
Прошу простить за скептическое отношение.
Сам микроконтроллеры не программировал, и тонкостей не знал (про отсутствие сдвига на некотором железе), поэтому судил со своей x86-й колокольни :)

)) Никаких проблем)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории