Reputation: 282
I'm trying to make a calculator that performs arithmetic operations with negative numbers. This code right here is used to convert inputted numbers into ASCII values. I want to modify this program to perform 2's complement conversion if the input is negative and it should result in desired output.
Currently this is the flow of my calculator:
-1+2=66675 (should be 1)
-1-1=656745 (should be -2)
-1*-1=66757 (should be 1)
someone advises me that i should modify this part of my code to perform what i want. I've tried my best but it's not working. can u help me with this one? oh by the way, im really new to assembly..
CONVERT_ASSCII PROC NEAR
MOV AH , BYTE PTR RESULT ;MOVE FIRST TWO BYTE OF RESULT TO AX
MOV AL , BYTE PTR RESULT + 1
;AT FIRST CHECK IF AX IS POSITIVE OR NEGETIVE
TEST EAX , 8000H ;CHECK THE LAST BIT . IF THATS 1 THEN AX IS NEG , OTHERWISE THATS POSITIVE
MOV EDI , 0 ;AT FIRST SET OUR FLAG TO ZERO
JZ EAX_POSITIVE ;AX IS POSITIVE
NEG EAX ;CALCULATE NEGETIVE OF AX
MOV EDI , 1 ;DI INDICATES THAT AX IS NEG
EAX_POSITIVE :
MOV ECX , 10
LEA ESI , ASSCII_NUM
ADD ESI , 29 ;MOVE TO THE LAST SPACE
MOV EBP , 0 ;THIS IS THE COUNTER OF CHARS
ASSCII_LOOP : MOV EDX , 0
DIV ECX
OR DL , 30H ;MAKE REMINDER ASSCII
MOV [ESI] , DL ;PUT ASSCII IN ASSCII_NUM
DEC ESI
INC EBP ;ADD ONE TO THE CHAR'S COUNTER
CMP EAX , 0 ;IF AX > 0 GOTO
JA ASSCII_LOOP ;ASSCII_LOOP
CMP EDI , 0 ;CHECK IF THAT WAS A NEGETIVE NUMBER
JZ REST ;IF THATS NOT NEGETIVE GOTO REST
MOV DL , '-'
MOV [ESI] , DL ;ADD A MINES SIGN TO THE STRING
DEC ESI
INC EBP
REST :
LEA EDI , ASSCII_NUM
;MOVE THE ASSCII CODE TO IT'S RIGHT PLCAE IN ASSCII_NUM
ORDER_ASSCII : INC ESI
MOV AL , BYTE PTR [ESI]
MOV BYTE PTR [EDI] , AL
INC EDI
DEC EBP
CMP EBP , 0
JA ORDER_ASSCII
MOV CL , '$'
MOV BYTE PTR [EDI] , CL ;AT LAST PUT A DOLLOR SIGN AT THE END OF ASSCII_NUM
RET
CONVERT_ASSCII ENDP
Upvotes: 2
Views: 10430
Reputation: 71506
Understand the problem then apply a langauge to it. I would write it in C first then later in assembly.
you mention ASCII, but I dont see your conversion from ascii.
Say for example when you said "-1+2" does that mean your input is the ASCII characters for those items which is
0x2D,0x31,0x2B,0x32
One way you can parse this is:
The 0x2D you need to recognize as a minus sign an operation, then you hit the number 1 which is 0x31 in ascii. Assuming these are decimal numbers then strip off the 0x30, and with 0xF for example. The next character is a +, 0x2B, an operator, so now you can go back and take your complete number 1 and apply the operator before to it. But you need a register size are these 8 bit values or 16 bit or 32 bit or 64 bit? An 8 bit 1 is 0x01, 16 is 0x0001, etc, when you negate that you get 0xFF or 0xFFFF or 0xFFFFFFFF, etc. So the current operator is a +, 0x2B, next character is 0x32 the number 2, and with 0xF to extract the 2. next character the end of string, so now apply the operation -1, 0xFF if 8 bit, plus 2, 0x02 if 8 bit is 0xFF+0x02 = 0x101, when clipped to 8 bits is 0x01, the result -1 + 2 = 1, and then you have to get that back to ascii, in this case 1 + 0x30 = 0x31, but it is only that easy for numbers less than 10.
"-1*-1" is 0x2D,0x30,0x2A,0x2B,0x30
the problem comes when you see the two operators in a row 0x2A then 0x2B, in this case as a human we know that what is meant is that in both cases the minus sign negates the number that follows, then you perform the multiply.
Larger numbers if you support them have to be handled as well.
"12+34" 0x31,0x32,0x2B,0x33,0x34
0x31 is a number strip off the 0x1, but 0x32 is also a number so multiply 0x1 times 10, then add the 2 stripped from the 0x32 giving a 0xC in whatever is accumulating that number (decimal 12), then the plus sign 0x2B then the other number handled the same way strip the 3 out of 0x33 multiply by 10, add the 4 stripped out of 0x34 giving decimal 34 (0x22), then add those two numbers 0x0C + 0x22 = 0x2E (46 decimal). in that case I assume the desired result is 0x34,0x46, the ascii string for "46". To get there though you need to divide 0x2e by 10 since it is larger than 10, to get 4 the first digit, the remainder (modulo 10) is 6, that is not larger than 10 so you are done with the conversion make the 6 a 0x36.
Using AND, OR, ADD, NOT, and maybe NEG operations if your target has a NEG (otherwise use not and add 1). remember that xoring with all ones is a NOT operation if you dont have a direct NOT instruction. (basically the fundamental operations available in the instruction set you want to target) Implement and test your algorithm in a programming language you are very comfortable with or at least one that supports these kinds of operations and byte processing, get the algorithm working and complete then simply convert each and, add, not, sub, etc operation in your high level language into assembly. It may (WILL) take many iterations of the solution in the high level language before it resembles a form that translates easily to assembly. if you are not strong in assembly now then you multiply the complexity and time it will take to complete this task. Trying to create and debug the algorithm and learn assembly all at the same time is not twice as much work, but more like four or more times as much work. divide and conquer. Develop the algorithm in a controlled environment, then implement it in the target language.
-1+2=66675 (should be 1) 0xFFFF...FFFF + 0x000...00002 = 0x1000000...000001, clips to 0x0000...00001 (I am using arbitrary register sizes) 66675 = 0x10473. not quite sure how you got to a number like that.
-1-1=656745 (should be -2) 0xFFFFF....FFFFF + 0xFFFFFF...FFFFF = 0xFFFFFFF...FFFFFFE. 656745 = 0xA0569
-1*-1=66757 (should be 1)
I would be very curious to know what the result of these
-1+1
-1+3
-2+1
-2+2
-1*-2
-1*-3
-2*-1
-2*-2
are using your calculator. You might start to see a pattern in the results when you do that.
divide the problem in half, are you sure you are computing the right result for your math operation and it is only the result to ascii that is broken? Or is the result to ascii working and the math operation is broken? hex is easy, octal is even easier to convert to and you dont need to do the backward thing for a quick check, can reverse it by hand after you see the result
while(ax)
{
dl = (ax&7)+0x30;
string[ptr++]=dl;
ax>>=3;
}
string[ptr]=0;
then display the string. reverse the string by hand, use a calculator to convert from octal to decimal and check the result. A minus two (-2) would be 0xFFFFF....FFFFE so in octal you would see, in reverse order 67777777777....7777777. so a calculator would get you to the hex value 0xFFFFF....FFFE once you reversed the string. the positive results should be easy to see though with a calculator.
(yes I am well aware you are using x86 with 16 bit registers)
Upvotes: 1