Please tell me your LOGIC

Programming, for all ages and all languages.
Post Reply
sulaiman

Please tell me your LOGIC

Post by sulaiman »

Hi to all ASM guru here.

I wish to seek some help from your people.

I wish to know is there any other LOGIC ways to put (ascii number) in memory data into register.

example,
let says,

intA   db 33,34,35
intB   db 36,37,38

so basically, the intA is (345h) in ASCII and intB is (678h) in ASCII
so, the question is, how if we want to add this two numbers to become 9BDh?

I assume we must be able to make the register AX,BX,CX or DX to contain
these two number.

eg.
AX = 345
BX = 678

so how can we put these numbers into register (in numeric form) so that we can add them later?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Please tell me your LOGIC

Post by Pype.Clicker »

well, you cannot do it in one shot. But basically, you will loop the 'string of numbers', substracting '0' (or 0x30) to each of them to get the value of each digit, and accumulate x = x * 10 + digit in some register.

When you're done with one value, you do the same with the other one, and then add ...

There's an intermediary representation called 'Binary Coded Decimal' which the x86 CPU supports and that is able to tell you that 0x00030405 + 0x00060708 is 0x01000203

btw, except if you have specific reasons to do things at once, i suggest you split the problem in int_to_str(str_to_int("345") + str_to_int("678") ...
Schol-R-LEA

Re:Please tell me your LOGIC

Post by Schol-R-LEA »

Pype.Clicker wrote: well, you cannot do it in one shot. But basically, you will loop the 'string of numbers', substracting '0' (or 0x30) to each of them to get the value of each digit, and accumulate x = x * 10 + digit in some register.
Actually, the formula would be [tt]x += base[sup]order[/sup] * c[/tt], where 'order' is the place in the number from right to left. Even this isn't complete; since Sulaiman specifically said he needed it to work with hex, it would also need to convert the letter-numerals to their correct numeric value. A full algorithm would be:

[tt]s == the string holding the number
c == the current character
x == the current loop index
accumulator == the accumulated final value
cvalue == the numeric value of the current character to be converted
base == the base of the number to be converted
order == the order of the numeral in question (that is, the unit place, the tens place, the hundreds place, and so on)
size == the size of the number

order = 0;
accumulator = 0;

find the size of the number held in string s;

for x from (size - 1) down to 0
c = s[sup]x[/sup] forced to upper case;

if c is a number then
cvalue = ASCII value of c - ASCII '0';
else, since c must then be a valid letter-numeral,
cvalue = ASCII value of c - ASCII 'A';

accumulator += base[sup]order[/sup] * cvalue;
increment order;
end for

return accumulator;
[/tt]

The good news is, so long as you have the suitable handling for letter-numerals, the algorithm is pretty much general for any base. Here's a version of it in C (including a test program):

Code: Select all

#include <stdio.h>
#include <ctype.h>
#include <math.h>

#define INT_OFFSET  0x30   /* ASCII offset for integers */
#define CHAR_OFFSET 0x41   /* ASCII offset for capital letters */

#define max(x, y) (((x) >= (y)) ? (x) : (y))  

int string2int (char s[], int base)
{
    char c; 
    int i;
    int cvalue;
    int order = 0;     /* the order of the numeral in the number */
    int acc = 0;

    for (i = (size_of_number(s, base) - 1); i >= 0; i--, order++)
    {
        c = toupper(s[i]);
        if (isdigit(c))
           cvalue =  (int) c - INT_OFFSET;
        else
           /* since you know it is before the end of the integer,
              assume it is a valid letter-numeral */
           cvalue = (int) c - CHAR_OFFSET + 10;
           
        acc += pow(base, order) * cvalue;
    }
    return acc;   
}

int size_of_number(char s[], int base)
{
    int i;
    char c;
    int base_offset = max(0, base - 10);
    
    c = toupper(s[0]);
    
    for (i = 1; 
         (isdigit(c)) || (isalpha(c) && (((int) c - CHAR_OFFSET) < base_offset));
         i++)
         c = toupper(s[i]);
         
    i--;
    return i;
}


#define NUMCOUNT 6
#define NUMSIZE  3

int main()
{
    char numbers[NUMCOUNT][NUMSIZE] = {"5", "10", "24", "30", "1A", "bf"};
    int count;
    int base;
    
    puts("Original Strings:");
    for(count = 0; count < NUMCOUNT; count++)
        printf(" %s", numbers[count]);
    puts("\n");
    
    puts("Number sizes in base 16:");
    for(count = 0; count < NUMCOUNT; count++)
        printf(" %d", size_of_number(numbers[count], 16));
    puts("\n");
    
    for (base = 8; base <= 16; base++)
    {
        printf("base %d:", base);
        for(count = 0; count < NUMCOUNT; count++)
            printf(" %d", string2int(numbers[count], base));
        puts("\n");
    }
}
If you prefer the Intel style "Nh" notation over the C style "0xN" notation, you may want to use a different size_of_number() function when you write your assembly version.
There's an intermediary representation called 'Binary Coded Decimal' which the x86 CPU supports and that is able to tell you that 0x00030405 + 0x00060708 is 0x01000203
True, but that only works for base 10 numerals.
swth

Re:Please tell me your LOGIC

Post by swth »

(logic is a noun)

there is no point in adding ascii characters
(subtracting is another story)

from the moment you press a key (on the keyboard)
the internal ascii representation is a byte (8 bits)

a number's representation doesnt change accordingly to its base,
which means that functions like printf are responsible for the look

why would anyone convert a string to a number ??
a 1000 character string is nothing,
but a 1000 digit number sucks!

usually 'a' is enough for a preprocessor to extract its ascii value,
not by calculation, but some sort of indexing database
in another database 'a' might have a different value
so to keep things portable just use the god damn thing

db is a macro
quite surprising for a so called assembly
this is supposed to be low level staff
db "hello world" is totally unacceptable

what's wrong with

inta db 'a'
intb db 0x17h
mov ax, inta or sth

really ?!

you dont mess with decimals
all transcripts are to binary, then you do whatever ..

ever heard of

sscanf(s,"%d",&n);
sprintf(s,"%d",n);
atoi() etc

what is your problem anyway ???
reading asm tutorials .. who could imagine!
BI lazy

Re:Please tell me your LOGIC

Post by BI lazy »

you may be right, swth, but be careful of the ghosts you invoke with your arrogant manner to write. Your writing leads me to the impression of a big moron thinking he 's the worlds one and only navel.

In short words, you sound like a git.
Tim

Re:Please tell me your LOGIC

Post by Tim »

Plus it's confusing:
db "hello world" is totally unacceptable
swth, your posts are beginning to do more harm than good.

please sort them out
or you may find
a visit from the delete-o-tron
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Please tell me your LOGIC

Post by Candy »

Schol-R-LEA wrote:
There's an intermediary representation called 'Binary Coded Decimal' which the x86 CPU supports and that is able to tell you that 0x00030405 + 0x00060708 is 0x01000203
True, but that only works for base 10 numerals.
If you code the bits yourself, the divide & multiply also work for different bases (second byte of the opcode is base).
sulaiman

Re:Please tell me your LOGIC

Post by sulaiman »

since we want to mul 16 or 10 or 8 for different base.

any idea, we just SHL or SHR the number and + or - the value to get the result.

example,

intA db 3,4,5 ;assume decimal (minus 30h already)

so, we want to make this three hundred and forty-five in our register AX.

is there any way, we just SHL or SHR the first number (3) and plus / minus the result so that we can obtain 300 // three hundred in our register?

and SHL or SHR the second number (4) and + / - the result so that we can get 40.

any formula?

because I don't think the big software company out there will use times 10 to obtain the result, coz if the user have a number eg. 10000000000000000000000000012 in memory,
how are they going to translate it into register?

It means they got to multiple 10 for around 28 times.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Please tell me your LOGIC

Post by Candy »

sulaiman wrote: because I don't think the big software company out there will use times 10 to obtain the result, coz if the user have a number eg. 10000000000000000000000000012 in memory,
how are they going to translate it into register?
They're going to convert it to either 4294967295 (YES! finally know 2^32 out of the back of my head!) being the largest number a 32-bit int can represent, or to 18446744073709551615 being the largest number a 64-bit int can represent (nope, used calc.exe for that one...).

If it's put into a floating point register, it's going to be hard to convert, but I'd suggest looking into the FILD instruction on x86es, that does just that. Page 3-251 on the intel manual volume 2A.

anyway, the only reason you'd use these functions is when the user enters a number (how fast did users type again? 50 MBit of inbound traffic?) or when files containing plaintext numbers are loaded. I can nearly guarantee you, that barely ever happens.
mystran

Re:Please tell me your LOGIC

Post by mystran »

Candy wrote: They're going to convert it to either 4294967295 (YES! finally know 2^32 out of the back of my head!) being the largest number a 32-bit int can represent, or to 18446744073709551615 being the largest number a 64-bit int can represent (nope, used calc.exe for that one...).
..or they are going to represent it with multiple 32-bit or 64-bit numbers, just like we humans use multiple base-10 decimals to represent a big number. Isn't especially hard after all..
Neptune

Re:Please tell me your LOGIC

Post by Neptune »

>> because I don't think the big software company out there will use times 10 to obtain the result

Not necessarily. You might be suprised (I wouldn't) to find that many commercial applications are riddled with inefficiencies like that. It all depends on the quality of the coding, the development language(s) used, the underlying implementation of any third-party code that may be in use, etc, etc, etc.

Anyway, to multiply a number by 10 using shifts is easy - just use the algorithm:

x = (x << 3) + (x << 1);

To multiply by 16, just shift the number left 4 times.

To convert a string of hexadecimal characters to an unsigned integer in C might look something like:

Code: Select all

 unsigned hextoint(const char * s)
{
  unsigned val, result = 0;
 
     while(*s == ' ') 
    {
      ++s;
    }  
    
     while(*s != 0 && *s != '\n')
    {
      val = *s++;
     
         if(val >= 'A' && val <= 'F') // convert to lowercase
        {
          val += 0x20;
        } 
         
         if(val >= 'a' && val <= 'f')
        {
          val -= 'a';
          val += 0x0a;
        }        
         else if(val >= '0' && val <= '9')
        {
          val -= '0';
        } 
         else
        {
          return 0;
        }         
        
      result = (result << 4) + val;
    }
 
  return result;        
}

- Sebastian
sulaiman

Re:Please tell me your LOGIC

Post by sulaiman »

and i am thinking about a better to do things like this.

Code: Select all


; yup, this is the algorithm i search for.
x = (x << 3) + (x << 1);
i will use your algorithm in my next post... :)
but i am thinking something else here,
how about byte to byte operation.

eg.
consider (something like this) not real code, just to describe
the idea in my mind.


n1= 1234567890 in memory (each integer is one byte size)
n2= 9876543210 in memory (each integer also one byte size)
nTotal = times 11 db 0;

// GOL = get offset length i == 10
i = (GOL n1 > GOL n2) ? GOL n1 : GOL n2;
p = i++ // index for storing the total one.., should be one byte more than the longest length "n" byte.

start:
mov ax,[n1 + i]
if( [n1 + i] || [n2 + i ] == 0 ) {
mov [nTotal + p], n1 or n2 who is not zero
jmp start
}
add ax, [n1+i], [n2+i], [nTotal+p]
pushf
mov [nTotal+p], ax
p--
i--
popf
jc got_plus_one
jmp start

got_plus_one:
mov [nTotal+p], 1
jmp start





num2reg.asm
======

Code: Select all

org 100h

jmp   start

num1      db   3,4,5,20   ; to ease the problem, i use decimal number directly.
num2      db   6,7,8,20   ; 20 equal to termination
numTotal   dw   0      ; numTotal must contain 1023 // 3FF in the end

byte_num_add:
   xor   ax,ax
   xor   bx,bx
   byte_num_add_start:
      cmp   byte [si],20
      je   byte_num_add_return
      mov   al,[si]
      push   ax
      mov   ax,10
      mul   bx
      pop   bx
      add   bx,ax
      inc   si
      jmp   byte_num_add_start
   
   byte_num_add_return:
      ret
   
start:
   mov   si,num1         ; offset of num1
   call   byte_num_add
   mov   [numTotal],bx
   mov   si,num2         ; offset of num2
   call   byte_num_add
   mov   ax,[numTotal]
   add   bx,ax
   mov   [numTotal],bx
   jmp   finish

finish:
   mov   ah,4ch
   int 21h
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Please tell me your LOGIC

Post by Candy »

sulaiman wrote:

Code: Select all

; yup, this is the algorithm i search for.
x = (x << 3) + (x << 1);
i will use your algorithm in my next post... :)
but i am thinking something else here,
how about byte to byte operation.
As I see you want to use assembly, try:

Code: Select all

mov eax, x
next_number:
shl eax, 1
lea eax, [eax + eax*4 - 48]
add eax, [number]     ; the ascii number
cmp [number], end_character
jne next_number
Any good compiler would generate this for you though.
Post Reply