2014-10-04 4 views
2

можно заменить заявление if/else инструкциями и if (скажем, мы работаем на C)? Если это возможно, можете ли вы поделиться примером. Так, скажем, у меня естьзамените if/else с оператором while/if

if (cond1) 
    exec1 
else 
    exec2 

И я очень хочу, чтобы избавиться от if/else и просто использовать if/while конструкции.

Достаточно ли для полного языка Turing иметь инструкции while/if (для потока управления)?

Как мне это сделать с if/else конструкциями?

(это не домашнее задание, это из любопытства)

+0

Если это не предназначено для можно использовать для некоторого кода для гольфа. Я не понимаю, почему вы хотите это сделать. Также я не вижу способа реализовать ветку 'else', используя какую-то конструкцию цикла while. Если ветка if-then да, но не другая. – datenwolf

+1

if-else может быть заменен коммутатором и условными операторами. –

ответ

0

Они эквивалентны, если cond1 не изменяется в exec1.

if (cond1) exec1 else exec2 

if (cond1) exec1 
if (!cond1) exec2 

Нет, когда это необходимо.

1

Это несколько неуклюжим, но при условии, что выполнение любой отрасли не изменяет состояние, можно заменить, если-то еще построить с парой Whiles: Пусть оригинал:

if (cond) { 
    exec1(); 
else { 
    exec2(); 
} 

Он может быть заменен только if с:

if (cond) { 
    exec1(); 
} 
if (!cond) { 
    exec2(); 
} 

Или с while с:

while (cond) { 
    exec1(); 
    break; 
} 
while (!cond) { 
    exec2(); 
    break; 
} 
0

Условный, иначе может быть заменен: с помощью Если:

если (условие cond1 верно) {

выполнить exec1;

}

если // условие ложно

{ выполнить exec2 ((условие cond1 верно!));

}

использованием В то время как цикл:

в то время как (условие истинно cond1) {

выполнить exec1;

в то время как (!(условие cond1 истинно)) // условие ложно

{ выполнить exec2;

}

+2

Вы забыли перерыв, иначе ваше время не остановилось – sqlab

+0

Нет, условие проверяется на каждой итерации, условие также изменяется внутри циклов while. Напр. Итератор ++; – ABcDexter

1

Вам даже не нужно while, вам просто нужно, чтобы иметь возможность сравнить и быть в состоянии расшириться, другими словами, if и goto. В следующей программе, функции test_normally() и test_subnormally() эквивалентны:

#include <stdio.h> 

void exec1(void) 
{ 
    puts("exec1() called"); 
} 

void exec2(void) 
{ 
    puts("exec2() called"); 
} 

void exec3(void) 
{ 
    puts("exec3() called"); 
} 

void test_normally(void) 
{ 
    int cond1 = 0; 
    int cond2 = 1; 
    int i = 5; 

    /* First if test */ 

    if (cond1) 
     exec1(); 
    else 
     exec2(); 

    puts("First if test over."); 

    /* Second if test */ 

    if (cond2) 
     exec1(); 
    else 
     exec2(); 

    puts("Second if test over."); 

    /* While test */ 

    while (i > 0) { 
     exec3(); 
     --i; 
    } 

    puts("Loop test over."); 
} 

void test_subnormally(void) 
{ 
    int cond1 = 0; 
    int cond2 = 1; 
    int i = 5; 

    /* First if test */ 

    if (!cond1) 
     goto cond1_false; 

    exec1(); 
    goto cond1_end; 

cond1_false: 
    exec2(); 

cond1_end: 
    puts("First if test over."); 

    /* Second if test */ 

    if (!cond2) 
     goto cond2_false; 

    exec1(); 
    goto cond2_end; 

cond2_false: 
    exec2(); 

cond2_end: 
    puts("Second if test over."); 

    /* While test */ 

loop_start: 
    if (!(i > 0)) 
     goto loop_end; 

    exec3(); 
    --i; 
    goto loop_start; 

loop_end: 
    puts("Loop test over."); 
} 

int main(void) 
{ 
    test_normally(); 
    putchar('\n'); 
    test_subnormally(); 
    return 0; 
} 

и выход:

[email protected]:~/src/sandbox$ ./goto 
exec2() called 
First if test over. 
exec1() called 
Second if test over. 
exec3() called 
exec3() called 
exec3() called 
exec3() called 
exec3() called 
Loop test over. 

exec2() called 
First if test over. 
exec1() called 
Second if test over. 
exec3() called 
exec3() called 
exec3() called 
exec3() called 
exec3() called 
Loop test over. 
[email protected]:~/src/sandbox$ 

Сравнивая две функции, надеюсь, вы можете понять, почему if и while и все их друзья лучше чем альтернативы.

test_subnormally() на самом деле очень близок к тому, что делает процессор, после того, как ваш источник C скомпилирован в машинный код. Вот результат сборки test_normally() от ССЗ на 64 битном процессоре Intel - вы можете увидеть, что почти отображение взаимно-однозначное соответствие между инструкциями по сборке и источника C для другой функции, test_subnormally():

.LC3: 
    .string "First if test over." 
.LC4: 
    .string "Second if test over." 
.LC5: 
    .string "Loop test over." 
    .text 
    .globl test_normally 
    .type test_normally, @function 
test_normally: 
.LFB3: 
    .cfi_startproc   # // Function entry 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    subq $16, %rsp 
    movl $0, -8(%rbp) # // -8(%rbp) is cond1 
    movl $1, -12(%rbp) # // -12(%rbp) is cond2 
    movl $5, -4(%rbp) # // -4(%rbp) is i 
    cmpl $0, -8(%rbp) # if (!cond1)  
    je .L5     # goto cond1_false; 
    call exec1   # exec1(); 
    jmp .L6     # goto cond1_end; 
.L5:      # cond1_false: 
    call exec2   # exec2(); 
.L6:      # cond1_end: 
    movl $.LC3, %edi  # // move "First if test over" to %edi 
    call puts   # puts("First if test over"); 
    cmpl $0, -12(%rbp) # if (!cond2) 
    je .L7     # goto cond2_false; 
    call exec1   # exec1(); 
    jmp .L8     # goto cond2_end; 
.L7:      # cond2_false: 
    call exec2   # exec2(); 
.L8:      # cond2_end: 
    movl $.LC4, %edi  # // move "Second if test over" to %edi 
    call puts   # puts("Second if test over"); 
    jmp .L9     # goto loop_start; 
.L10:      # loop_body: 
    call exec3   # exec3(); 
    subl $1, -4(%rbp) # --i; 
.L9:      # loop_start: 
    cmpl $0, -4(%rbp) # if (!(i > 0)) ... 
    jg .L10    # ...goto loop_body; 
    movl $.LC5, %edi  # // move "Loop test over" to %edi 
    call puts   # puts("Loop test over"); 
    leave     # // Function exit 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 

Компилятор здесь решил поместить фрагменты цикла в несколько иной порядок, но кроме этого он читает почти так же, как источник C для test_subnormally(). Основная причина, по которой мы имеем if, и while, и их друзей в C точно так, что нам не нужно писать код, который выглядит так, но этот уровень простоты и спагетти-кода - это то, что в конечном итоге завершает выполнение процессоров (и это все, что вам нужно для завершения Turing), поэтому у нас есть компилятор, чтобы превратить что-то, что выглядит более понятным и поддерживаемым для людей в виде беспорядка, с которым отлично справляются процессоры.

2

Для общей замены if() ... else ... конструкции, вы можете кэшировать результат условия:

int condition = cond1; 
if(condition) exec1; 
if(!condition) exec2; 

Таким образом, можно избежать проблем с побочными эффектами в cond1 и exec1.

Что касается Вашего вопроса о Тьюринга полноте:
Как Пол Гриффитс заметки, if() и goto достаточны. Однако, так же как и if() и рекурсия. Вы можете заменить любой while(cond1) exec1; цикл с самостоятельной рекурсивной функции:

void loopy(/*whatever state the loop touches*/) { 
    if(cond1) { 
     exec1; 
     loopy(/*pass on the current state*/); 
    } 
} 

Этот факт сильно злоупотребляли в функциональных языках, как шепелявость и схемы. Когда вы изучаете программирование на этих языках, вас учат писать рекурсии таким образом (хвостовая рекурсия), что компилятор может понять, что вы намеревались написать цикл и соответственно оптимизировать ...

Смежные вопросы