My code stops adding by converting from hexadecimal to decimal

4

I want to convert a string of 6 bytes in hexadecimal to a float

   float desencapsularArchivo::hex2dec(string aConvertir)
    {
    int cantHex = aConvertir.size();

    float decimal = 0;

    for(int hexNum = 0;hexNum < cantHex; hexNum++)
    {
        char piv = aConvertir.at(hexNum);

        float hex;

        switch(piv)
        {
        case 'A': case 'a':
            hex = 10;
            break;
        case 'B': case 'b':
            hex = 11;
            break;
        case 'C': case 'c':
            hex = 12;
            break;
        case 'D': case 'd':
            hex = 13;
            break;
        case 'E': case 'e':
            hex = 14;
            break;
        case 'F': case 'f':
            hex = 15;
            break;
        default:
            hex = (int)piv - 48;
        }
        decimal = decimal + hex * pow(16, cantHex - hexNum - 1);
    }

    return decimal;

}

If I want to enter for example the string 00805f181015 the result is: 551351222272 instead of: 551351226389

According to my tests, the last 4 characters of the hexadecimal are missing, but I do not know why it does not.

It is worth mentioning that to print use cout << "Decimal: " << setprecision(0) << fixed << decimal;

    
asked by codeKiller 21.02.2018 в 19:38
source

2 answers

3

Your algorithm is correct; the types used are incorrect. You are having a problem of loss of precision when using floating point numbers. As already mentioned in another question , not all decimal numbers are representable with the IEEE floating-point format .

In particular the number 551351226389 does not have accurate representation in floating point, so the value that is approaching is 551351222272 1 , you can check it on this webpage . If you change all your float of your code by integer types ( long or long long ) , the error disappears.

  • A loss of accuracy of 0.000001%.
  • answered by 22.02.2018 в 09:26
    2

    If you want to convert a 6-byte string into a number you will need one that supports 6 bytes ...% co_of% occupy 8 then it should be more than enough ... another thing is that the algorithm fails you for another reason.

    And to show, a button. The following example perfectly converts, among others, the problematic number ( uint64_t ):

    unsigned long long Convertir(std::string const& cadena)
    {
      unsigned long long numero = 0;
    
      for( char c : cadena )
      {
        numero *= 16;
    
        if( c >= 'a' )
          numero += c - 'a' + 10;
        else
          numero += c - '0';
      }
    
      return numero;
    }
    
    int main()
    {
      std::cout << Convertir("1") << '\n'
                << Convertir("10b") << '\n'
                << Convertir("123456") << '\n'
                << Convertir("999998") << '\n'
                << Convertir("00805f181015") << '\n';
    }
    

    PD: Use unsigned long long for not loading additional libraries, but the effect is the same as when using 00805f181015

        
    answered by 22.02.2018 в 11:08