学生が組み合わせの計算を練習できるように、アセンブリ言語(MASM)でプログラムを作成しました。プログラムは階乗を再帰的に計算します。nとrを受け取り、(n = r)!、n !、およびr!を取得するcombinationsという手順を使用します。階乗と呼ばれるプロシージャを呼び出すことによって。階乗は再帰的です。
.data
n DWORD ?
r DWORD ?
result DWORD ?
answer DWORD ?
divisor DWORD ?
.code
MAIN PROC
(いくつかの予備手順の呼び出し)
push OFFSET divisor ;ebp+20
push n ;ebp+16
push r ;ebp+12
push OFFSET result ;ebp+8
call combinations
;*************************************************
; combinations calls factorial (3 times) to calculate n!, r!, and (n-r)!.
; combinations calculates n!/(r!(n-r)!) , and stores the value in result.
; receives: accepts n and r by value and result by address.
; returns: none
; preconditions: none
; registers changed: eax, ebx, edx
;*************************************************
combinations PROC
push ebp
mov ebp,esp
mov eax, [ebp+16] ;find (n-r)!
sub eax, [ebp+12]
mov ebx, eax
push ebx
call factorial
pop ebx
mov edx,[ebp+20] ;move (n-r)! into result
mov [edx],eax
mov ebx, [ebp+12] ;find r!
push ebx
call factorial
pop ebx
mov edx,[ebp+20]
mov ebx, [edx]
mul ebx ;r!*(n-r)!, store product in eax
mov ebx, [ebp+20]
mov [ebx], eax ;store product in divisor variable
mov ebx, [ebp+16] ;find n!
push ebx
call factorial
pop ebx
mov edx,[ebp+20]
mov ebx,[edx] ;move value of divisor into ebx
mov edx, 0
div ebx ;divide n! by divisor (r!*(n-r)!)
mov ebx, [ebp+8]
mov [ebx],eax ;move quotient into result
pop ebp
ret 16
combinations ENDP
;*************************************************
; calculates factorial recursively
; receives:
; returns: factorial solution in eax
; preconditions: none
; registers changed: eax
;*************************************************
factorial PROC
mov eax,dword ptr [esp+4]
cmp eax,1
jle endRecursive
dec eax
push eax
call factorial
mov esi,dword ptr [esp+4]
mul esi
endRecursive:
ret 4
factorial ENDP
すべてが期待どおりに進み、必要な値を取得しています。ただし、すべての計算が完了し、プログラムが組み合わせ手順の最後に「ret 16」というステートメントに到達すると、次の例外が発生します。
Project.exeの0x76f915deで未処理の例外:0xC0000005:アクセス違反。
デバッガーで実行し、計算を間違えた場合にreturnステートメントを変更しようとしましたが、これまで試したことは何も機能しませんでした。じっと見つめすぎたのかもしれませんが、どんなアイデアでもよろしくお願いします。前もって感謝します。
更新: デバッガーでebpとespを追跡するだけです。プログラムが最後の階乗呼び出しから出たとき、espはebpの+12であるため、階乗の呼び出しごとに+4が追加されます。その結果、プログラムがpop ebpにヒットすると、ebpは本来あるべき場所ではなくrを指しています。これを修正する方法について何か提案はありますか?