ошибка сегментации в сборке x86 реализация гипотезы collatz

#recursion #assembly #collatz

#рекурсия #сборка #collatz

Вопрос:

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

Мой псевдокод для этого, который реализует его рекурсивно (мы можем использовать только рекурсию)

 int threexplusone(int x){
    if(x == 1){
      return 0;
    }else{
      if(x % 2 == 0){
        return (threexplusone(x/2) 1);
      }else{
        return (threexplusone(3*x 1) 1);
      }
    }
}
  

Мой код выглядит так

 threexplusone:
    push rbx        ;store the rbx to stack
    mov rax, 0      ;store the base case
    cmp rdi, 1      ;compare the input with 1
    je done         ;finished the loop if equal to 1
    jmp threexplusone_recursive ;jump to the recursion

threexplusone_recursive:
    mov rbx, rdi        ;move rdi's value to rbx
    sar rbx, 1      ;divide x by 2
    sub rbx, rdi        ;substitute to get the remainder
    cmp rbx, 0      ;compare to check if the remainder is 0
    je  even        ;start the even instruction
    jne odd         ;start the odd insturction

even:
    sar rdi,1       ;divided the input by 2
    xor rax,rax
    call threexplusone  ;do the recursion

    inc rax         ;add the result by one
    jmp done        ;

odd:
    imul rdi,3      ;multiply x by 3
    add rdi, 1      ;add x by 1
    xor rax, rax
    call threexplusone  ;do the recursion
        
    inc rax     ;add the result by one
    jmp done        ;

done:
    pop rbx
    ret
  

Я тестирую его в cpp-файле, который

1. Запросите входное значение x, которое является положительным целым числом для передачи подпрограмме,

2. Запросите входное значение n, которое представляет собой количество раз для вызова подпрограммы

3. Запустите подпрограмму один раз и сохраните результат

4. Запустите подпрограмму n раз с параметром x в качестве входных данных

5. Выведите количество итераций, которое потребовалось для того, чтобы целое число сошлось к 1.

 int main(){
    int x;
    cout << "Enter a number: " << endl;
    cin >> x;
    int n; 
    cout << "Enter iterations of subroutine: " << endl;
    cin >> n;
    int result = threexplusone(x);
    for(int i = 0; i < n; i  ){
        result = threexplusone(x);
    }
    cout << result << endl;
    
    return 0;
}
  

Ожидаемый результат должен быть

 Enter a number: 
100
Enter iterations of subroutine: 
30
Steps take: 25
  

Insetead, у меня ошибка segmentaiotn

 Enter a number: 
100
Enter iterations of subroutine: 
30
Segmentation fault (core dumped)
  

Я прохожу через отладчик, вот что он мне говорит

 Program received signal SIGSEGV, Segmentation fault.
0x000000000040133a in odd ()

  

Похоже, проблема в нечетной части установки

 odd:
    imul rdi,3      ;multiply x by 3
    add rdi, 1      ;add x by 1
    xor rax, rax
    call threexplusone  ;do the recursion
        
    inc rax     ;add the result by one
    jmp done    
  

Мне интересно, какая часть моей сборки может быть причиной? Спасибо

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

1. Вы прошли через свой код с помощью отладчика? Знаете ли вы, на какой строке происходит сбой и как выглядит стек вызовов в этот момент?

2. В чем смысл «итераций подпрограммы»? Я бы предположил, что это верхний предел количества разрешенных вами рекурсивных вызовов, а не «вызывать функцию так много раз».

3. Наконец, есть что-то подозрительное с вашим тестом на равномерность в threexplusone_recursive: похоже, вы выполняете x — x / 2 и проверяете, равен ли результат 0. Почему не просто test rbx, rbx , а затем отправка на основе четного флага?

4. Как сказал Ботье, тест на равномерность выглядит неправильно (больше похоже x/2-x == 0 ), что означает, что у вас неограниченная рекурсия. Вы можете протестировать бит0 для проверки равномерности (например test rdi, 1 ).

5. @Botje: PF (флаг четности) устанавливается в соответствии с горизонтальным xor младших 8 бит, а не младшим битом. (т.е. en.wikipedia.org/wiki/Parity_bit в вычислительной технике, а не в математике). Если вы этого хотите, test dil, 1 / jnz odd . Или sar rbx, 1 и переход на CF (бит смещен).