Оптимальная реализация таблицы истинности
Я определил таблицу истинности, такую как приведенная ниже
prev_state| input1 | input2 |next_state| Action
(def/new) |(Disable/Enable)|(Off/On)| |
def | D | Off | def | Nothing
def | D | On | def | Nothing
def | E | Off | def | Nothing
def | E | On | new | call function1
new | D | Off | def | call function2
new | D | On | def | call function2
new | E | Off | def | call function2
new | E | On | new | Nothing
Мне было интересно, какое минимальное количество проверок вам нужно для этого.
Думаю ли я использовать карту Карно, такую как следующая:
00| 01| 11| 10
-----------------
0 | A | A | B | A |
-----------------
1 | C | C | A | C |
-----------------
Где A ничего не соответствует, B для вызова function1 и C для вызова function2
В соответствии с тем, что я вижу, у вас есть 2 комбинации по 2 A и по одному Всего 3 для A 1 для B и 2 комбинации из 2 C
Означает ли это, что минимальное количество сравнений составляет 3+1+2=6? Но поскольку А ничего не делают, минимальная реализация потребует только 3 комбинации для В и С?
Тестовая реализация
if (prev_state == new && input1 == disable) {
function2();
}
else if (prev_state == new && input2 == Off) {
function2();
}
else if (input1 == enable && input2 == On) {
function1();
}
Также теперь, когда я вижу это, которое лучше выше или этот:
if ((prev_state == new && input1 == disable) || (prev_state == new && input2 == Off)) {
function2();
}
else if (input1 == enable && input2 == On) {
function1();
}
Спасибо за тех, кто предложил таблицу поиска, которая является O(1), но занимает место в памяти. Теперь я понимаю, что предпочел бы иметь решение, не использующее дополнительную память. Согласны ли вы с тем, что использование карт Карно является допустимым методом для получения минимального количества сравнений?
4 ответа
Мне было интересно, каково минимальное количество проверок, которое вам нужно достичь...
Нуль. Используйте справочную таблицу
void f_Nothing(void) {
; // do nothing
}
void f_function1(void) {
; // something interesting
}
void f_function2(void) {
; // something interesting
}
int main(void) {
typedef void (*fun_type)(void);
fun_type f[2][2][2] = { //
{{f_Nothing, f_Nothing}, {f_Nothing, f_function1}},
{{f_function2, f_function2}, {f_function2, f_Nothing}}};
bool prev_state, input1, input2;
//...
f[prev_state][input1][input2]();
Позже OP прокомментировал поиск решения, которое... не использует дополнительную память.
if ( (input1 == E && input2 == ON) && (prev_state == def)) function1();
if (!(input1 == E && input2 == ON) && (prev_state == new)) function2();
// or
if (input1 == E && input2 == ON) {
if (prev_state == def) function1();
} else {
if (prev_state == new) function2();
}
Если поведение статично, делать тесты бесполезно, вы можете
используйте трехмерный массив, где каждое значение является парой следующего состояния и действия, первое измерение - prev_state 0/1, второй вход 1 D/E -> 0/1, третий вход2 выключен / включен -> 0/1
но поскольку ваши входные данные очень ограничены, вы также можете закодировать 3 индекса только в один =
prev_state * 4 + input1 * 2 + input2
и используйте простой вектор размера 8. Как предполагает Шверн в замечании, вы также можете выполнить переключение / регистр для результатаprev_state * 4 + input1 * 2 + input2
Вы можете удалить несколько повторных тестов, но имеет ли это большое значение на практике, зависит от оптимизации компилятора.
if (prev_state == new) {
if (input1 == disable || input2 == Off) {
function2();
}
} else {
if (input1 == enable && input2 == On) {
function1();
}
}
Или же:
if (input1 == disable || input2 == Off) {
if (prev_state == new) {
function2();
}
} else {
if (prev_state == def) {
function1();
}
}
Я бы сделал что-то вроде ниже.
int check = (int)((prev_state == new) << 2 | (input1 == E)<<1 | (input2 == on));
/*def | E | On | new | call function1 == 3
new | D | Off | def | call function2 == 4
new | D | On | def | call function2 == 5
new | E | Off | def | call function2 == 6 */
if (check == 4 || check == 5 || check == 6)
function2();
else if (check == 3)
function1();