Math imprecision

Hey, I tried to write a small Hex to Dec converter:

void hextodec(){
  float result = 0;
  int tmp = 0;
  float dec = 0;
  for(int i = 9; i > 1; i--){
    switch((int)chip[i]){
     case 48: dec = 0; break;
     case 49: dec = 1; break;
     case 50: dec = 2; break;
     case 51: dec = 3; break; 
     case 52: dec = 4; break;
     case 53: dec = 5; break;
     case 54: dec = 6; break;
     case 55: dec = 7; break;
     case 56: dec = 8; break;
     case 57: dec = 9; break;
     case 65: dec = 10; break;
     case 66: dec = 11; break;
     case 67: dec = 12; break;
     case 68: dec = 13; break;
     case 69: dec = 14; break;
     case 70: dec = 15; break;
    }
    result = result+dec*pow(16,tmp);
    tmp++;
  }
  Serial.print(" Binary Notation: ");
  Serial.print(result);
}

But the results aren't exact. For example: 0x001FBB82 = 2079618 But I get: 0x001FBB82 = 2079615.87

Another one: 0x0098A42C = 10003500 But I get: 0x0098A42C = 10003488.00

How is this possible?

pow(16,tmp);

It's possible because of that. Lose it. Lose all floating point.

Lose the switch too - arithmetic is simpler.

At first I used only integers. But the pow() function needs a floating base.

/edit: How should I calculate it without a switch?

case 48: dec = 0; break;
     case 49: dec = 1; break;
     case 50: dec = 2; break;
     case 51: dec = 3; break; 
     case 52: dec = 4; break;
     case 53: dec = 5; break;
     case 54: dec = 6; break;
     case 55: dec = 7; break;
     case 56: dec = 8; break;
     case 57: dec = 9; break;

Notice a pattern?

How should I calculate it without a switch?

1 << 0 = 1
1 << 1 = 2
1 << 2 = 4
1 << 3 = 8
1 << 4 = 16

AWOL:

case 48: dec = 0; break;

case 49: dec = 1; break;
     case 50: dec = 2; break;
     case 51: dec = 3; break;
     case 52: dec = 4; break;
     case 53: dec = 5; break;
     case 54: dec = 6; break;
     case 55: dec = 7; break;
     case 56: dec = 8; break;
     case 57: dec = 9; break;



Notice a pattern?

Yes… Well here is it with two if statements

    if(((int)chip[i] >=48) && ((int)chip[i] <= 57))
      dec = (int)chip[i]-48;
    if(((int)chip[i] >=65) && ((int)chip[i] <= 70))
      dec = (int)chip[i]-55;

AWOL:

How should I calculate it without a switch?

1 << 0 = 1
1 << 1 = 2
1 << 2 = 4
1 << 3 = 8
1 << 4 = 16

I honestly have no idea what this should mean.

To avoid the pow() function, should I write my own function which uses integers, or is there another possibility?

OK, how about this

1 << 0 = 1. 20 = 1
1 << 1 = 2. 21 = 2
1 << 2 = 4 22 = 4
1 << 3 = 8. 23 = 8
1 << 4 = 16. 24 = 16

Any bells ringing?

Or, try something like this:

#define UlongFromBinaryString(str)      PowerOfTwoFromString(str, 1)
#define UlongFromHexString(str)      PowerOfTwoFromString(str, 4)
 
unsigned long PowerOfTwoFromString(char *input, int shift)
{
    unsigned long val = 0;
    char upperLimit = 'a' + (1 << shift);
    while (*input) {
        char c = tolower(*input++);
        unsigned long digit = (c > 'a' && c < upperLimit) ? c - 'a' + 10 : c - '0';
        val = (val << shift) | digit;
    }
    return val;
 }

void setup() {
  Serial.begin(115200);
  Serial.println(UlongFromHexString("0x001FBB82"));
}

void loop() {
  
}

AWOL:
OK, how about this

1 << 0 = 1. 20 = 1
1 << 1 = 2. 21 = 2
1 << 2 = 4 22 = 4
1 << 3 = 8. 23 = 8
1 << 4 = 16. 24 = 16

Any bells ringing?

Oh well I understood the sequence but didn’t knew that this is an operator. I’ve never heard of bitewise shift, until know. Thank you for explaining this…

Well I’ve figured it out now with the help op bitewise shift (quite awesome this thing).

void hextodec(){
  long int result = 0;
  long int tmp = 0;
  long int dec = 0;
  for(int i = 9; i > 1; i--){
    
    if(((int)chip[i] >=48) && ((int)chip[i] <= 57))
      dec = (int)chip[i]-48;
    if(((int)chip[i] >=65) && ((int)chip[i] <= 70))
      dec = (int)chip[i]-55;
    result = result+(dec<<tmp);
    tmp += 4;
  }
  Serial.print(" Binary Notation: ");
  Serial.print(result);
}

Thank you!

To make it easier to rememberdec = (int)chip[i]-48; is better written dec = chip[i]-'0';
Glad you got it figured out :slight_smile:

how is the chip[] defined? (or did I miss it)

I haven't posted it here.

char chip[14];

OK thanks,

note: posting the whole sketch often makes it easier to reproduce and analyze the problem