简体   繁体   中英

Arithmetic operations with large numbers in assembly

I got a task to write an assembly routine that can be read from C and declared as follows:

extern int solve_equation(long int a, long  int b,long  int c, long int *x, long int *y);

that finds a solution to the equation

a * x + b * y = c

In -2147483648 <x, y <2147483647 by checking all options.

The value returned from the routine will be 1 if a solution is found and another 0 .

You must take into consideration that the results of the calculations: a * x, b * y, a * x + b * y can exceed 32 bits.

.MODEL SMALL
.DATA
C DQ ?
SUM DQ 0
MUL1 DQ ?
MUL2 DQ ?
X DD ?
Y DD ?
.CODE
.386
PUBLIC _solve_equation
_solve_equation PROC NEAR
PUSH BP 
MOV BP,SP
PUSH SI
MOV X,-2147483648 
MOV Y,-2147483648 
MOV ECX,4294967295
FOR1:
        CMP ECX,0
        JE FALSE
        PUSH ECX
        MOV Y,-2147483648 
        MOV ECX,4294967295
FOR2:
        MOV SUM,0
        CMP ECX,0
        JE SET_FOR1

        MOV EAX,DWORD PTR [BP+4]
        IMUL X
        MOV DWORD PTR MUL1,EAX
        MOV DWORD PTR MUL1+4,EDX

        MOV EAX,DWORD PTR [BP+8]
        IMUL Y
        MOV DWORD PTR MUL2,EAX
        MOV DWORD PTR MUL2+4,EDX

        MOV EAX, DWORD PTR MUL1
        ADD DWORD PTR SUM,EAX
        MOV EAX, DWORD PTR MUL2
        ADD DWORD PTR SUM,EAX

        MOV EAX, DWORD PTR MUL1+4
        ADD DWORD PTR SUM+4,EAX
        MOV EAX, DWORD PTR MUL2+4
        ADD DWORD PTR SUM+4,EAX

        CMP SUM,-2147483648
        JL SET_FOR2
        CMP SUM,2147483647
        JG SET_FOR2
        MOV EAX,DWORD PTR [BP+12]
        CMP DWORD PTR SUM,EAX
        JE TRUE
SET_FOR2:       
            DEC ECX
            INC Y
            JMP FOR2
SET_FOR1:
            POP ECX
            DEC ECX
            JMP FOR1
FALSE:
            MOV AX,0
            JMP SOF
TRUE:
            MOV SI,WORD PTR [BP+16]
            MOV EAX,X
            MOV DWORD PTR [SI],EAX
            MOV SI,WORD PTR [BP+18]
            MOV EAX,Y   
            MOV DWORD PTR [SI],EAX
            MOV AX,1
SOF:
        POP SI
        POP BP
        RET
        _solve_equation ENDP
        END 

Is this the right way to work with large numbers?

I get argument to operation or instruction has illegal size when I try to do:

MOV SUM,0
CMP SUM,-2147483648
CMP SUM,2147483647

main code:

 int main() { long int x, y, flag; flag = solve_equation(-5,4,2147483647,&x, &y); if (flag == 1) printf("%ld*%ld + %ld*%ld = %ld\\n", -5L,x,4L,y,2147483647); return 0; } 

output

 -5*-2147483647 + 4*-2147483647 = 2147483647 

I`m using dosbox 0.74 and tcc

You're using 16-bit code, so 64-bit operand-size isn't available. Your assembler magically associates a size with sum , because you defined it with sum dq 0 .

So mov sum, 0 is equivalent to mov qword ptr [sum], 0 , which of course won't assemble in 16 or 32-bit mode; you can only operate on up to 32 bits at once with integer operations.

(32-bit operand-size is available in 16-bit mode on 386-compatible CPUs, using the same machine encodings that allows 16-bit operand size in 32-bit mode. But 64-bit operand size is only available in 64-bit mode. Unlike 386, AMD64 didn't add any new prefixes or anything to previously-existing modes, for various reasons.)


You could zero the whole 64-bit sum with an SSE store, or even compare with SSE4.2 pcmpgtq , but that's probably not what you want.

It looks like you want to check if 64-bit sum fits in 32 bits. (ie if it is a sign-extended 32-bit integer).

So really you just need to check that all 32 high bits are the same and match bit 31 of the low half.

mov  eax, dword ptr [sum]
cdq                              ; sign extend eax into edx:eax
                                 ; i.e. copy bit 31 of EAX to all bits of EDX
cmp  edx, dword ptr [sum+4]
je   small_sum

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM