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 "0x
N" 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.