0

This is an almost exact duplicate of my own question a few weeks ago.

Convert Hex to Decimal when no datatype can hold the full number

This time, it is the reverse. I have the number (in a handy null terminated string) and I need the bytes that make this number. However, I am working in a 32 bits architecture for a micro controller, therefore I don't have the possibility of using the atoi, as the number is larger than 32 bits.

Does anyone have an idea on how to reverse the algorithm provided in the first link, as to get back the original result? My modulo arithmetic skills are failing me.

Quick Example: 155.207.231.135 to 0x[24][23][12][66][9F] (the brackets separate the bytes)

Community
  • 1
  • 1
Manuel Ferreria
  • 1,216
  • 1
  • 13
  • 23

3 Answers3

1

You can do something similar to BigInt division.

a = atoi of lower 7 decimal digits
b = atoi of remaining upper decimal digits


for (int i = 0; i < 5; i++)
{
    a += 10000000 * (b % 256);
    b /= 256;
    Result[i] = a % 256;
    a /= 256;
}
matthock
  • 629
  • 1
  • 4
  • 15
0

You'll need assembler for this one. Pseudocode:

int low = 0 // lower 32 bit
int high = 0 // higher 32 bit

for (int i=0; i<string.length(); i++) {
    int digit = string.get(i) - '0';
    int a = low;
    int b = high;
    a <<= 1; b += overflow;             // *2
    a <<= 1; b += overflow;             // *4
    a += low; b += overflow; b += high; // *5
    a <<= 1; b += overflow;             // *10
    a += digit; b += overflow;          // +digit
    low = a; high = b;
}

So basically, you create a 64bit register using two 32bit ints. For each loop, you:

    value *= 10 + digit;

Afterwards, you only need to skip the 0 bytes at the beginning of the resulting value to get the bytes you seek.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • I don't get what "overflow" is supposed to be. – Manuel Ferreria Aug 13 '09 at 15:44
  • Every CPU has an overflow or carry bit that is set when the last operation didn't fit into the involved data types. If you have a byte with the value 0xff and you shift that right once, the carry bit will be set (since the topmost bit was set) and the byte will be 0xfe. – Aaron Digulla Aug 13 '09 at 15:47
  • Often, you have "ADDC" (add with carry), so you could "ROR a; AADC #0, b;" or there is a branch: "ROR a; BCC #label; ADD #1, b; #label" so the ADD is skipped if the carry bit is not set. – Aaron Digulla Aug 13 '09 at 15:49
  • Sorry, I do not fully understand assembly yet, I code in C. However, in my compiler, I have a function called shift_right (and left) which returns me the value popped during the operation. I think it could be analogous to what you are trying to accomplish here. – Manuel Ferreria Aug 13 '09 at 16:17
  • Analogous to the overflow bit (as I can't seem to find this register it in my micro controller datasheet) – Manuel Ferreria Aug 13 '09 at 16:18
  • Basically, this code emulates a 64bit "multiply by 10". Maybe your library already contains a 64bit multiply. – Aaron Digulla Aug 14 '09 at 09:08
0

Just parse the string from left to right, multiplying the previous result by ten and adding the digit.

Here's some code in C# to show the concept. First two methods to to math on an array:

static void Mul(byte[] data, int num) {
   int n = 0;
   for (int i = data.Length - 1; i >= 0; i--) {
      n += (int)data[i] * num;
      data[i] = (byte)n;
      n >>= 8;
   }
}

static void Add(byte[] data, int num) {
   for (int i = data.Length - 1; num > 0; i-- ) {
      num += (int)data[i];
      data[i] = (byte)num;
      num >>= 8;
   }
}

Then you just do:

string s = "155207231135";
byte[] result = new byte[16];
foreach (char c in s) {
   Mul(result, 10);
   Add(result, c - '0');
}

The result is in the result array, padded with zero bytes to the left.

It shouldn't bee to hard to translate to C... :)

Guffa
  • 687,336
  • 108
  • 737
  • 1,005