我正在使用 Irvine32 库开发一个汇编程序,根据用户输入(范围从 1 到 13 行)打印帕斯卡三角形。虽然程序正确显示前几行,但从第 5 行开始,输出变成乱码,并且未按预期显示二项式系数。
; ---------------------------------------------------------------------------------
; Name: Pascal's Triangulator Program
;
; Description:
; This program prompts the user to enter the number of rows (1-13) they wish to
; print of Pascal's Triangle. It calculates and displays each row with numbers
; separated by spaces. The program includes input validation to ensure the number
; of rows entered is within the specified range.
;
; ---------------------------------------------------------------------------------
INCLUDE Irvine32.inc
; --------------------------------
; Constants
; --------------------------------
MAX_ROWS EQU 13
MIN_ROWS EQU 1
; --------------------------------
; Data Segment
; --------------------------------
.data
; Program Messages
introMsg BYTE "Pascal's Triangulator - Programmed by Cameron Brooks!", 0
introDesc BYTE "This program will print up to 13 rows of Pascal's Triangle, per your specification!", 0
promptMsg BYTE "Enter total number of rows to print [1...13]: ", 0
farewellMsg BYTE "Thank you for using Pascal's Triangulator. Goodbye!", 0
invalidInputMsg BYTE "Invalid input. Please enter a number between 1 and 13.", 0
; Row Formatting
currentRowMsg BYTE "Row ", 0
rowNumberMsg BYTE ": ", 0
; Variables
userRows DWORD ? ; Stores user input
currentRow DWORD ? ; Stores current row index
kValue DWORD ?
binCoeff DWORD ?
.code
main PROC
; Introduction
CALL Introduction
; Prompt user for input
MOV EDX, OFFSET promptMsg
CALL WriteString
; Read integer input
CALL ReadInt
MOV [userRows], EAX ; Store input in userRows
; Validate input (1 <= userRows <= 13)
CMP EAX, MIN_ROWS
JL InvalidInput
CMP EAX, MAX_ROWS
JG InvalidInput
; Initialize loop counter in EBX
MOV EBX, 0 ; EBX = loop counter (starts at 0)
RowLoop:
; Compare loop counter with userRows
CMP EBX, [userRows]
JGE EndProgram ; Exit loop if all rows are printed
; Print "Row X: "
MOV EDX, OFFSET currentRowMsg
CALL WriteString ; Print "Row "
; Print row number (EBX)
PUSH EAX ; Preserve EAX
MOV EAX, EBX ; Load currentRow into EAX
CALL WriteDec ; Print row number
POP EAX ; Restore EAX
; Print ": "
MOV EDX, OFFSET rowNumberMsg
CALL WriteString ; Print ": "
; Set currentRow to EBX
MOV [currentRow], EBX ; Update currentRow
; Print the current row
CALL PrintPascalRow ; Print the current row
; Print newline
CALL CrLf
; Increment loop counter
INC EBX ; EBX++
; Jump back to loop
JMP RowLoop ; Repeat the loop
InvalidInput:
; Handle invalid input
MOV EDX, OFFSET invalidInputMsg
CALL WriteString
CALL CrLf
JMP EndProgram
EndProgram:
; Farewell message
MOV EDX, OFFSET farewellMsg
CALL WriteString
CALL CrLf
; Exit program
EXIT
main ENDP
; ---------------------------------------------------------------------------------
; Procedure: Introduction
; Description:
; Displays the program title and a brief description.
;
; Registers Modified:
; - EAX, EDX
; ---------------------------------------------------------------------------------
Introduction PROC
; Display Introduction Message
MOV EDX, OFFSET introMsg
CALL WriteString
CALL CrLf
; Display Introduction Description
MOV EDX, OFFSET introDesc
CALL WriteString
CALL CrLf
CALL CrLf
RET
Introduction ENDP
; ---------------------------------------------------------------------------------
; Procedure: PrintPascalRow
; Description:
; Prints all binomial coefficients for the current row in Pascal's Triangle.
;
; Registers Modified:
; - EAX, EBX, ESI, EDI, EDX
; ---------------------------------------------------------------------------------
PrintPascalRow PROC
; Preserve EAX, EDX, ESI, and EDI to avoid disrupting the main loop
PUSH EAX ; Preserve EAX
PUSH EDX ; Preserve EDX
PUSH ESI ; Preserve ESI
PUSH EDI ; Preserve EDI
MOV ESI, 0 ; Initialize k to 0
RowElementLoop:
MOV EBX, [currentRow] ; EBX = n (current row index)
CMP ESI, EBX
JG EndRow ; If k > n, end row
; Set kValue
MOV [kValue], ESI ; k = current element index
CALL nChooseK ; binCoeff = nCk
; Print Binomial Coefficient
MOV EAX, [binCoeff] ; Load bin_coeff into EAX
CALL WriteDec ; Print bin_coeff
; Print Space
MOV DL, 32 ; ASCII space character (decimal 32)
CALL WriteChar ; Print space
; Increment k
INC ESI ; k++
; Loop back to print next element
JMP RowElementLoop
EndRow:
; Restore preserved registers
POP EDI ; Restore EDI
POP ESI ; Restore ESI
POP EDX ; Restore EDX
POP EAX ; Restore EAX
RET
PrintPascalRow ENDP
; ---------------------------------------------------------------------------------
; Procedure: nChooseK
; Description:
; Calculates the binomial coefficient "n Choose k" using the multiplicative formula.
;
; Parameters:
; - n is stored in 'currentRow'.
; - k is stored in 'kValue'.
;
; Preconditions:
; - 'currentRow' and 'kValue' contain valid integers where 0 <= k <= n.
;
; Postconditions:
; - 'binCoeff' contains the value of "n Choose k".
;
; Registers Modified:
; - EAX, EBX, ECX, EDX, ESI, EDI, EFLAGS
; ---------------------------------------------------------------------------------
nChooseK PROC
; Save Callee-Saved Registers
PUSH EBX
PUSH ESI
PUSH EDI
; Retrieve n and k
MOV EAX, [currentRow] ; EAX = n
MOV EBX, [kValue] ; EBX = k
; Handle k = 0 or k = n
CMP EBX, 0
JE SetOne
CMP EBX, EAX
JE SetOne
; If k > n, set binCoeff to 0
CMP EBX, EAX
JG SetZero
; Calculate nCk using Multiplicative Formula
MOV ECX, 1 ; Initialize counter i=1
MOV EAX, 1 ; Initialize binCoeff=1
CalcLoop:
CMP ECX, EBX
JG StoreResult
; Calculate (n - i + 1)
MOV ESI, [currentRow] ; ESI = n
SUB ESI, ECX ; ESI = n - i
ADD ESI, 1 ; ESI = n - i + 1
; Multiply binCoeff by (n - i + 1)
MUL ESI ; EAX = EAX * (n - i +1)
; Divide binCoeff by i
MOV EDI, ECX ; EDI = i
XOR EDX, EDX ; Clear EDX for DIV
DIV EDI ; EAX = EAX / i
; Increment i
INC ECX ; i++
JMP CalcLoop
StoreResult:
MOV [binCoeff], EAX ; Store the result
JMP EndCalculation
SetOne:
MOV [binCoeff], 1 ; binCoeff =1
JMP EndCalculation
SetZero:
XOR EAX, EAX ; EAX =0
MOV [binCoeff], EAX ; binCoeff=0
EndCalculation:
; Restore Callee-Saved Registers
POP EDI
POP ESI
POP EBX
RET
nChooseK ENDP
END main
预期行为:
当我输入1到5之间的数字时,程序会以适当的间距正确显示帕斯卡三角形的相应行。例如,输入 4 会产生:
Row 1: 11
Row 2: 121
Row 3: 1331
Row 4: 14641
Thank you for using Pascal's Triangulator. Goodbye!
实际行为:
但是,当我输入大于 4 的数字(例如 5 或 13)时,输出会变成乱码,例如 13 会导致:
Row 1: 11
Row 2: 121
Row 3: 1331
Row 4: 14641
Row 5: 1510
10
51
Row 6: 1615201561
Row 7: 172135#35#2171
Row 8: 12856870F568281
Row 9: 19 36$84T126~126~84T36$9 1
Row 10: 110
45-120x210╥252ⁿ210╥120x45-10
1
Row 11: 111
557165Ñ330J462╬462╬330J165Ñ55711
1
Row 12: 112
66B220▄495∩792924£792495∩220▄66B12
1
Thank you for using Pascal's Triangulator. Goodbye!
问题详情:
第 0-4 行: 正确显示前六行,没有适当的间距。
第 5-13 行:
我尝试过的:
问题:
附加信息:
汇编器和环境:在 32 位 Windows 环境中将 MASM 与 Irvine32 库结合使用。
之前的尝试:遵循之前的建议来保留额外的寄存器并消除自定义输出程序,但问题仍然存在。
任何有关解决这些输出问题的帮助或见解将不胜感激!
感谢 Peter Cordes 提供的宝贵反馈!
您对
WriteChar
程序的正确寄存器使用的观察正是我解决我的帕斯卡三角程序所面临的问题所需要的。
最初,我的程序正确显示帕斯卡三角形直到第 5 行。但是,从第 6 行开始,输出因串联数字和随机符号而变得乱码。这主要是由于二项式系数之间的空格字符处理不正确。
正如您所指出的,Irvine32 库中的
WriteChar
过程期望字符位于 AL
寄存器中,而不是 DL
中。在我的原始代码中,我将空格字符移动到 DL
,这导致了错误的字符打印。
更正注册
WriteChar
:
原代码:
; Print Space
MOV DL, 32 ; ASCII space character (decimal 32)
CALL WriteChar ; Print space
更新代码:
; Print Space
MOV AL, 32 ; ASCII space character (decimal 32)
CALL WriteChar ; Print space
说明:
通过将空格字符 (
32
) 移入 AL
寄存器而不是 DL
,WriteChar
程序可以正确打印空格,确保二项式系数之间的正确分离。
已验证的注册保存:
EAX
、EDX
、ESI
、EDI
)并在退出前恢复。这可以防止过程调用(如 WriteDec
和 WriteChar
)产生意外的副作用。实施更改后,程序现在可以正确显示帕斯卡三角形,并且数字之间有适当的间距。以下是输入
13
行时的输出示例:
Pascal's Triangulator - Programmed by Cameron Brooks!
This program will print up to 13 rows of Pascal's Triangle, per your specification!
Enter total number of rows to print [1...13]: 13
Row 0: 1
Row 1: 1 1
Row 2: 1 2 1
Row 3: 1 3 3 1
Row 4: 1 4 6 4 1
Row 5: 1 5 10 10 5 1
Row 6: 1 6 15 20 15 6 1
Row 7: 1 7 21 35 35 21 7 1
Row 8: 1 8 28 56 70 56 28 8 1
Row 9: 1 9 36 84 126 126 84 36 9 1
Row 10: 1 10 45 120 210 252 210 120 45 10 1
Row 11: 1 11 55 165 330 462 462 330 165 55 11 1
Row 12: 1 12 66 220 495 792 924 792 495 220 66 12 1
Thank you for using Pascal's Triangulator. Goodbye!
了解图书馆程序:
彻底理解像
WriteChar
这样的库程序如何期望它们的参数是至关重要的。将数据放错到错误的寄存器中可能会导致意外的行为。
注册管理:
正确保存和恢复寄存器对于维护汇编语言中过程调用的数据完整性至关重要。
感谢 Peter 的指导,该程序现在可以按预期运行,准确地显示帕斯卡三角形,并且数字之间的间距适当。如果有人有进一步的建议或改进,我很乐意听到他们!