Таблицы истинности в коде?Как структурировать конечный автомат?
-
03-07-2019 - |
Вопрос
У меня есть (несколько) большая таблица истинности / конечный автомат, который мне нужно реализовать в моем коде (встроенный C).Я ожидаю, что спецификация поведения этого конечного автомата изменится в будущем, и поэтому я хотел бы, чтобы в будущем это можно было легко изменять.
Моя таблица истинности имеет 4 входа и 4 выхода.У меня все это есть в электронной таблице Excel, и если бы я мог просто вставить это в свой код с небольшим форматированием, это было бы идеально.
Я подумал, что хотел бы получить доступ к своей таблице истинности следующим образом:
u8 newState[] = decisionTable[input1][input2][input3][input4];
И тогда я мог бы получить доступ к выходным значениям с помощью:
setOutputPin( LINE_0, newState[0] );
setOutputPin( LINE_1, newState[1] );
setOutputPin( LINE_2, newState[2] );
setOutputPin( LINE_3, newState[3] );
Но для того, чтобы получить это, похоже, мне пришлось бы составить довольно запутанную таблицу следующим образом:
static u8 decisionTable[][][][][] =
{{{{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }},
{{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }}},
{{{ 0, 0, 1, 1 },
{ 0, 1, 1, 1 }},
{{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 }}}},
{{{{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 }},
{{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 }}},
{{{ 0, 1, 1, 1 },
{ 0, 1, 1, 1 }},
{{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 }}}};
Эти вложенные скобки могут несколько сбивать с толку - есть ли у кого-нибудь идея получше, как я могу сохранить красивую таблицу в своем коде?
Спасибо!
Редактировать на основе ответа ХУАГАГУА:
Используя объединение всех входных данных (спасибо - я хотел бы "принять" 3 или 4 из этих ответов), я думаю, что собираюсь попробовать это как двумерный массив.Я проиндексирую свой массив, используя небольшой макрос с битовым сдвигом:
#define SM_INPUTS( in0, in1, in2, in3 ) ((in0 << 0) | (in1 << 1) | (in2 << 2) | (in3 << 3))
И это позволит моему массиву таблицы истинности выглядеть следующим образом:
static u8 decisionTable[][] = {
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 1, 1 },
{ 0, 1, 1, 1 },
{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 },
{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 },
{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 },
{ 0, 1, 1, 1 },
{ 0, 1, 1, 1 },
{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 }};
И затем я могу получить доступ к своей таблице истинности следующим образом:
decisionTable[ SM_INPUTS( line1, line2, line3, line4 ) ]
Я попробую и посмотрю, что из этого получится.Я также заменю 0 и 1 на более полезные #defines, которые выражают значение каждого состояния, наряду с /**/ комментариями, объясняющими входные данные для каждой строки выходных данных.Всем спасибо за помощь!
Решение
Нет необходимости в многомерной таблице.При 4-битном => 4-битном отображении у вас может быть один массив u8 [16], отображающий входные данные в выходные.Поиск состояния будет намного дешевле, и вы можете извлекать отдельные биты с помощью некоторых операций сдвига и маски.
Если алгоритм заполнения строк легко кодифицировать, вы могли бы #define макрос для заполнения каждой строки по номеру индекса.
Другие советы
Я бы предложил либо то, либо другое (сначала предпочтительные подходы).:
- Используйте макрос для инициализации каждой "строки" - это скроет фигурные скобки внутри вызова макроса.
- Используйте комментарии для разделения строк.
- Используйте функцию init для явной инициализации контекста - возможно, используйте функции для инициализации каждого раздела.Это похоже на первый вариант, приведенный выше, но имеет тот недостаток, что перед использованием конечного автомата должна быть вызвана функция init.
Лично я бы прочитал это из файла конфигурации.Возможно, CSV, в который легко экспортировать из Excel.Или вы могли бы просто скопировать и вставить из Excel в обычный текст, который дает вам значения, разделенные пробелами, которые так же легко импортировать.
Это также означает, учитывая, что вы работаете с C, что вам не придется перекомпилировать свой код каждый раз при изменении таблицы решений.
если ваша таблица истинности состоит исключительно из логических значений, вы могли бы просто свернуть ее в список пар, например
1111,0000
1110,0110
...
для сжатия данных представьте значения в виде байтов (два nybbles)...
где / как сохранить его для программного кодирования в вашей конкретной конфигурации встроенной системы, можете сказать только вы ;-)
Если таблица истинности действительно имеет размер всего 4x4x4x4, то я бы использовал макросы.Если это когда-нибудь перерастет рамки этого, я бы использовал Рагель.Скорее всего, это сделает код на C меньше и быстрее, чем это сделаете вы.
Я не вижу никакой ссылки на текущее состояние, чтобы получить ваше выходное состояние.Это означает, что это не конечный автомат, а всего лишь таблица истинности.Имеется четыре входа, поэтому существует только 16 возможных комбинаций входных данных.Итак, таблица с 16 позициями должна это сделать.
Обычно, когда у вас возникает подобная проблема, ее пытаются свести к простой логической формуле.Я не понимаю, почему это было бы не лучшим подходом здесь.Это было бы намного компактнее и удобочитаемее, плюс у него есть потенциал быть быстрее (я полагаю, что несколько AND и OR выполнялись бы быстрее, чем набор умножений / сдвигов + доступ к памяти, необходимый для подхода с таблицей поиска).Самый простой способ свести эту таблицу к логической формуле - использовать K-Карта.