如何编写NASM汇编文件实现高精度除法?现有代码问题求助
NASM高精度除法:
greater_eq与mydiv函数问题排查与修正建议 我想用NASM实现高精度除法,先编写了一份C代码作为参考,目前已完成读、写及字符串反转功能,但greater_eq和mydiv函数存在逻辑错误,急需修正方案。
参考C代码
#include <cstdio> #include <cstring> static const int LEN = 1004; int a[LEN], b[LEN], c[LEN], d[LEN]; void clear(int a[]) { for (int i = 0; i < LEN; ++i) a[i] = 0; } void read(int a[]) { static char s[LEN + 1]; int x=0; int c=getchar(); while (c!='\n' && x<LEN-1) { s[x++] = c; c = getchar(); } s[x]='\0'; clear(a); int len = strlen(s); for (int i = 0; i < len; ++i) a[len - i - 1] = s[i] - '0'; } void print(int a[]) { int i; for (i = LEN - 1; i >= 1; --i) if (a[i] != 0) break; for (; i >= 0; --i) putchar(a[i] + '0'); putchar('\n'); } int greater_eq(int a[], int b[], int last_dg, int len) { if (a[last_dg + len] != 0){ printf("1!"); return 1; } for (int i = len - 1; i >= 0; --i) { if (a[last_dg + i] > b[i]){ printf("2!"); return 1;} if (a[last_dg + i] < b[i]){ printf("3!"); return 0;} } printf("4!"); return 1; } void div(int a[], int b[], int c[], int d[]) { clear(c); clear(d); int la, lb; for (la = LEN - 1; la > 0; --la) if (a[la - 1] != 0) break; for (lb = LEN - 1; lb > 0; --lb) if (b[lb - 1] != 0) break; if (lb == 0) { puts("> <"); return; } for (int i = 0; i < la; ++i) d[i] = a[i]; for (int i = la - lb; i >= 0; --i) { while (greater_eq(d, b, i, lb)) { for (int j = 0; j < lb; ++j) { d[i + j] -= b[j]; if (d[i + j] < 0) { d[i + j + 1] -= 1; d[i + j] += 10; } } c[i] += 1; } } } int main() { read(a); read(b); div(a, b, c, d); print(c); print(d); }
我的NASM数据定义
num1 times 100 db '0',0h num2 times 100 db '0',0h
问题函数1:greater_eq
greater_eq: ;a[]:num1,b[]:num2,last_ag:eax,len:ebx ;return in eax push ecx push edx push esi; preserve values mov esi,num1 add esi,eax add esi,ebx ;a[last+len] cmp [esi],‘0’ je compare jne greater compare: mov ecx,ebx ;i=len-1 dec ecx .loop: cmp ecx,0h jl greater mov esi,eax add esi,ecx mov edx,[num1+esi] ;a[last_eg+i] cmp edx,[num2+ecx] ;b[i] jg greater jl lesser dec ecx jmp .loop greater: pop esi pop edx pop ecx mov eax,1 ret lesser: pop esi pop edx pop ecx mov eax,0 ret
问题函数2:mydiv
mydiv: mov eax,sinput call strlen mov ecx,eax ;la ecx mov eax,dinput call strlen mov edx,eax ;lb edx jz rerurn_diff mov eax,sinput mov ebx,dinput mov esi,ecx ;i=0 sub esi,edx ;i=la-lb div_loop: cmp esi,0 jl return_n ; i<0结束循环 div_continue: push eax push ebx mov eax,esi ;i mov ebx,edx ;lb call greater_eq mov ebp,eax ;res pop ebx pop eax cmp ebp,0 jne div_sub dec esi ;i-- jmp div_loop div_sub: mov edi,0 ;j=0 div_sub_loop: cmp edi,edx ;j>=lb 退出 jge div_sub_add push ebp mov ebp,eax add ebp,esi add ebp,edi; a[i+j] ->byte[eax+esi+edi] ;1 push ebx add ebx,edi push eax mov ah,byte[ebp] mov al,byte[ebx] sub ah,al ;a[i+j] -= b[j] mov byte[ebp],ah pop eax pop ebx ;2 cmp byte[ebp],0 jl div_loop_fix div_sub_con: pop ebp inc edi ;j++ inc byte[c+esi] ;c[i]++ jmp div_continue div_loop_fix: dec byte[ebp+1] add byte[ebp],10 jmp div_sub_con div_sub_add: inc byte[c+esi] jmp div_continue return_n: ret rerurn_diff: mov eax,meg6 ret
核心问题与修正方案
针对greater_eq的修正点
- 字符与数值混淆:C代码数组存储的是
0-9的数值,但你的NASM中num1/num2存储的是'0'-'9'的ASCII字符,比较时必须先转成数值(减去'0'),否则是比较ASCII值,逻辑完全错误。- 示例修正:将
cmp [esi],‘0’改为mov al, [esi] sub al, '0' cmp al, 0;比较a[last_dg+i]和b[i]时,同样先转成数值再比较。
- 示例修正:将
- 循环边界校验:当前代码中
cmp ecx,0h jl greater逻辑正确,但需确保每次循环都正确获取对应位置的数值,而非字符。 - 寄存器顺序:
pop操作必须和push顺序相反(后进先出),当前代码顺序正确,无需修改。
针对mydiv的修正点
- 存储逻辑对齐C代码:必须将输入字符串转换为逆序数值数组(和C的
read函数逻辑一致),用字节存储0-9的数值,而非直接操作字符串。 - 减法与借位逻辑修正:
- C代码中是数值减法+借位,你的NASM直接操作字符减法,借位时
dec byte[ebp+1]会把字符变成非数值(比如'0'-1='/'),完全错误。必须基于数值数组实现减法:; 示例:数值数组的减法与借位 mov al, [d+i+j] sub al, [b+j] mov [d+i+j], al cmp al, 0 jge skip_borrow dec byte [d+i+j+1] add byte [d+i+j], 10 skip_borrow:
- C代码中是数值减法+借位,你的NASM直接操作字符减法,借位时
- 循环逻辑修正:C代码中是
while(greater_eq(...)),每次完整减法后才让c[i]加1,你的NASM在div_sub_loop中每循环一次j就加1,逻辑错误,需将inc byte[c+esi]移到完整减法循环外。 - 被除数复制逻辑补充:必须先将被除数数组复制到临时数组
d(和C代码一致),再进行除法操作。
快速落地建议
- 先确保所有计算用数组(
num1、num2、c、d)都是数值数组,从read函数输出时直接转成逆序数值存储。 - 完全对齐C代码的逻辑重写
greater_eq,直接操作数值字节。 - 重写
mydiv的核心循环,严格按照C代码的while+减法+借位逻辑实现。
内容的提问来源于stack exchange,提问作者fanrcis
相关产品推荐
相关产品推荐

