Под четностью битовой строки понимается, какое кол-во единичных бит — четное или нечетное — содержит эта строка. Правильнее было бы назвать его битом нечетности, т.к. нечетному кол-ву бит соответствует единичный бит четности, четному кол-ву — нулевой. Математически результат представляет собой сумму всех бит слова по модулю 2, т.е. над всеми битами выполняется операция
исключающее ИЛИ
. В стандартной библиотеке такой функции нет.
Я уже приводил один из способов проверки слова на четность (
подсчет установленных бит
). Там четность получается как побочный эффект вычислений и представляет собой младший бит значения возвращаемого функцией. Но если кол-во установленных бит вас не интересует, вычислять четность слова лучше с помощью более эффективных специализированных методов.
Классический метод вычисления для DWORD взят из книги Генри Уорена «Алгоритмические трюки для программистов», 2014 г.
x = x ^ (x >> 1);
x = x ^ (x >> 2);
x = x ^ (x >> 4);
x = x ^ (x >> 8);
x = x ^ (x >> 16);
x = x & 1;
Бит четности окажется в младшем разряде
х
. Последняя операция оставляет в двойном слове только этот разряд, обнуляя все остальные. Реализация на
STL
использует для расчетов только внутренние регистры:
FUNCTION FC10: VOID
TITLE = "Определение четности числа"
AUTHOR: Anakost //
FAMILY: SOHO //
NAME: BtParity // Bit + Parity
VERSION: 1.0 //
VAR_INPUT
Input: DWORD;
END_VAR
VAR_OUTPUT
Parity: DWORD;
END_VAR
BEGIN
NETWORK
TITLE = Вычисление четности числа DWORD
L #Input; //
// x = x ^ (x >> 1);
PUSH; //
SRD 1; //
XOD; //
// x = x ^ (x >> 2);
PUSH; //
SRD 2; //
XOD; //
// x = x ^ (x >> 4);
PUSH; //
SRD 4; //
XOD; //
// x = x ^ (x >> 8);
PUSH; //
SRD 8; //
XOD; //
// x = x ^ (x >> 16);
PUSH; //
SRD 16; //
XOD; //
// x = x & 1;
AD DW#16#1; //
T #Parity; //
END_FUNCTION
Функция работает правильно, но получение выходного результата в младшем бите слова
DWORD
мне показалось неудобным. Сначала нужно результат присвоить меркеру, а затем уже проверять младший бит в нем. С локальной переменной еще сложнее. Поэтому я немного изменил функцию, чтобы сразу получить битовый результат:
VAR_OUTPUT
Parity: BOOL;
END_VAR
...
SLD 1; // 1,2mkc // second bit <- bit parity
T STW; // 0,6mkc // RLO <- bit parity
= #Parity; // 0,4mkc // Parity <- RLO
Я изменил обьявление выхода на
BOOL
, и две последние строчки заменил на три новые. Дело в том, что бит
RLO
в статусном регистре
Simatic
находится во втором справа бите. Поэтому бит паритета сначала сдвигается на вторую позицию, а затем напрямую заносится в статусный регистр на место бита
RLO
. Следующая операция присваивает бит
RLO
выходу. Применять операцию
AD DW#16#1
здесь без надобности, т.к. изменение других битов статусного регистра нас не волнует (и не для всех возможно).
Можно и по другому, более традиционно и наглядно (как выяснилось, этот вариант еще и быстрее, увидел проставив типовое время выполнения):
...
AD DW#16#1; // 0,3mkc // ACCU1 and 1
A <>0; // 0,2mkc // RLO <- ACCU1 <> 0
= #Parity; // 0,4mkc // Parity <- RLO
Функция работает очень быстро, но в той же книге есть более оптимальный для
Simatic
алгоритм:
x = x ^ (x >> 1);
x = (x ^ (x >> 2)) & 0x11111111;
x = x mod 15;
x = x & 1;
Ее код на
STL
:
NETWORK
TITLE = Вычисление четности числа DWORD
L #Input; //
// x = x ^ (x >> 1);
PUSH; //
SRD 1; //
XOD; //
// x = (x ^ (x >> 2)) & 0x11111111;
PUSH; //
SRD 2; //
XOD; //
AD DW#16#11111111; //
// x = x mod 15;
L 15; //
MOD; //
// x = x & 1;
AD DW#16#1; //
T #Parity; //
Все вышесказанное о получении результата функции в булевом виде применимо и здесь..
Источник: http://we.easyelectronics.ru/plc/simatic-step-7-stl-bit-chetnosti-pariteta.html