汇编大整数斐波那契程序:超64位大整数打印实现求助
Nice work getting your big integer Fibonacci implementation running—storing the value correctly is half the battle! Printing those huge numbers is definitely a hurdle since standard printf can't handle arbitrary-precision values. Let's walk through how to implement the decimal conversion, focusing on the mod 10 and division-by-10 operations you need.
First, let's assume your big integer is stored as a little-endian byte array (common in assembly, where the lowest byte is at the start of the array), with a separate variable tracking its length in bytes. For example:
section .data big_num_len dd 0 ; Number of bytes in our big integer big_num db 0 ; Little-endian big integer data (big_num[0] = least significant byte)
Core Idea: Decimal Conversion via Repeated Division-by-10
To convert a big integer to a decimal string, we repeatedly divide the number by 10, capture the remainder (which gives us the next digit, 0-9), and build the string in reverse. Finally, we reverse the string to get the correct order. The key challenges are implementing mod 10 and divide by 10 for arbitrary-length integers.
1. Implement bigint_mod10 (Get the Last Digit)
Calculating N mod 10 for a big integer can be done iteratively from the most significant byte (MSB) to the least (LSB). Since each byte represents a value multiplied by 256^position, we can use the property:(a * 256 + b) mod 10 = ((a mod 10) * (256 mod 10) + b mod 10) mod 10
Since 256 mod 10 = 6, this simplifies to ((prev_remainder * 6) + current_byte) mod 10, which is fast and avoids overflow.
Here's the assembly implementation:
; Input: eax = pointer to big_num_len, ebx = pointer to big_num ; Output: dl = big_num mod 10 bigint_mod10: push eax push ebx push ecx push edx xor dl, dl ; Initialize remainder to 0 mov ecx, [eax] ; Load byte length of the big integer .mod_loop: ; Grab the current most significant byte (little-endian, so start at the end of the array) mov al, [ebx + ecx - 1] mov dh, dl ; Save previous remainder mov dl, al ; Current byte value ; Calculate (prev_remainder *6 + current_byte) mod10 mov al, dh mov bl, 6 mul bl ; ax = prev_remainder *6 add al, dl ; ax = (prev*6) + current_byte xor ah, ah mov bl, 10 div bl ; al = quotient, ah = new remainder mov dl, ah loop .mod_loop ; Process next byte pop edx pop ecx pop ebx pop eax ret
2. Implement bigint_div10 (Divide the Big Integer by 10)
Dividing a big integer by 10 works by processing each byte from MSB to LSB, calculating the quotient for that byte and carrying over the remainder to the next (less significant) byte. After division, we clean up any leading zeros to keep the length accurate.
; Input: eax = pointer to big_num_len, ebx = pointer to big_num ; Output: Big integer is updated to big_num /10, big_num_len adjusted if leading zeros exist bigint_div10: push eax push ebx push ecx push edx push esi mov ecx, [eax] ; Byte length xor esi, esi ; Initialize remainder to 0 mov edx, ebx add edx, ecx dec edx ; Point to MSB (end of array) .div_loop: mov al, [edx] ; Get current MSB mov ah, esi ; Previous remainder (0-9) ; Calculate (ah*256 + al) /10: al = quotient, ah = new remainder mov bl, 10 div bl mov [edx], al ; Save quotient back to the byte mov esi, ah ; Update remainder dec edx loop .div_loop ; Clean up leading zeros (adjust length if MSB becomes 0) .cleanup_zeros: mov ecx, [eax] cmp ecx, 0 je .done mov edx, ebx add edx, ecx dec edx cmp byte [edx], 0 jne .done dec dword [eax] jmp .cleanup_zeros .done: pop esi pop edx pop ecx pop ebx pop eax ret
3. Put It All Together: bigint_to_decimal
This function uses the above two helpers to build the decimal string, then reverses it to get the correct order. We also handle the special case where the big integer is 0 to avoid empty strings.
; Input: eax = pointer to big_num_len, ebx = pointer to big_num, ecx = pointer to output buffer ; Output: Buffer contains null-terminated decimal string of the big integer bigint_to_decimal: push eax push ebx push ecx push edx push esi push edi mov edi, ecx ; Save buffer start address ; Handle special case: big integer is 0 cmp dword [eax], 1 jne .not_zero cmp byte [ebx], 0 jne .not_zero mov byte [edi], '0' inc edi mov byte [edi], 0 jmp .done .not_zero: ; Build string in reverse (remainders are least significant digit first) .build_loop: call bigint_mod10 ; Get next digit (dl = 0-9) add dl, '0' ; Convert to ASCII char mov [edi], dl inc edi call bigint_div10 ; Divide number by 10 cmp dword [eax], 0 ; Stop when number is 0 jne .build_loop ; Reverse the string to get correct order dec edi ; Point to last valid character mov esi, ecx ; Point to first character .reverse_loop: cmp esi, edi jge .reverse_done ; Swap characters at esi and edi mov al, [esi] mov bl, [edi] mov [esi], bl mov [edi], al inc esi dec edi jmp .reverse_loop .reverse_done: mov byte [edi + 1], 0 ; Add null terminator .done: pop edi pop esi pop edx pop ecx pop ebx pop eax ret
Usage Example
To use this in your program, you'd call bigint_to_decimal with your big integer and a buffer, then print the buffer with printf:
section .data big_num_len dd 16 ; Example: 16-byte big integer big_num db 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 buffer times 256 db 0 ; Buffer for decimal string (plenty of space for large Fibs) format_str db "%s", 10, 0 section .text global main extern printf main: ; Assume your Fibonacci calculation has already filled big_num and big_num_len mov eax, big_num_len mov ebx, big_num mov ecx, buffer call bigint_to_decimal ; Print the result push buffer push format_str call printf add esp, 8 ; Exit program mov eax, 1 xor ebx, ebx int 0x80
Key Notes
- If your big integer uses a different storage format (e.g., big-endian, 32-bit words instead of bytes), adjust the loop directions and byte/word accesses accordingly—the core math logic stays the same.
- For 64-bit assembly, swap 32-bit registers (eax, ebx) with 64-bit ones (rax, rbx) and adjust memory addressing as needed.
- Make sure your buffer is large enough: Fibonacci numbers grow exponentially—for example, the 1000th Fibonacci number has 209 digits, so a 256-byte buffer is safe.
内容的提问来源于stack exchange,提问作者apilat

