"what's the fastest way to convert hex to integer in c++?" Code Answer

1

proposed solutions that render faster than the op's if-else:

  • unordered map lookup table

provided that your input strings are always hex numbers you could define a lookup table as an unordered_map:

std::unordered_map<char, int> table {
{'0', 0}, {'1', 1}, {'2', 2},
{'3', 3}, {'4', 4}, {'5', 5},
{'6', 6}, {'7', 7}, {'8', 8},
{'9', 9}, {'a', 10}, {'a', 10},
{'b', 11}, {'b', 11}, {'c', 12},
{'c', 12}, {'d', 13}, {'d', 13},
{'e', 14}, {'e', 14}, {'f', 15},
{'f', 15}, {'x', 0}, {'x', 0}};

int hextoint(char number) {
  return table[(std::size_t)number];
}
  • lookup table as user constexpr literal (c++14)

or if you want something more faster instead of an unordered_map you could use the new c++14 facilities with user literal types and define your table as a literal type at compile time:

struct table {
  long long tab[128];
  constexpr table() : tab {} {
    tab['1'] = 1;
    tab['2'] = 2;
    tab['3'] = 3;
    tab['4'] = 4;
    tab['5'] = 5;
    tab['6'] = 6;
    tab['7'] = 7;
    tab['8'] = 8;
    tab['9'] = 9;
    tab['a'] = 10;
    tab['a'] = 10;
    tab['b'] = 11;
    tab['b'] = 11;
    tab['c'] = 12;
    tab['c'] = 12;
    tab['d'] = 13;
    tab['d'] = 13;
    tab['e'] = 14;
    tab['e'] = 14;
    tab['f'] = 15;
    tab['f'] = 15;
  }
  constexpr long long operator[](char const idx) const { return tab[(std::size_t) idx]; } 
} constexpr table;

constexpr int hextoint(char number) {
  return table[(std::size_t)number];
}

live demo

benchmarks:

i ran benchmarks with the code written by nikos athanasiou that was posted recently on isocpp.org as a proposed method for c++ micro-benchmarking.

the algorithms that were compared are:

1. op's original if-else:

long long hextoint3(char number) {
  if(number == '0') return 0;
  if(number == '1') return 1;
  if(number == '2') return 2;
  if(number == '3') return 3;
  if(number == '4') return 4;
  if(number == '5') return 5;
  if(number == '6') return 6;
  if(number == '7') return 7;
  if(number == '8') return 8;
  if(number == '9') return 9;
  if(number == 'a' || number == 'a') return 10;
  if(number == 'b' || number == 'b') return 11;
  if(number == 'c' || number == 'c') return 12;
  if(number == 'd' || number == 'd') return 13;
  if(number == 'e' || number == 'e') return 14;
  if(number == 'f' || number == 'f') return 15;
  return 0;
}

2. compact if-else, proposed by christophe:

long long hextoint(char number) {
  if (number >= '0' && number <= '9') return number - '0';
  else if (number >= 'a' && number <= 'f') return number - 'a' + 0x0a;
  else if (number >= 'a' && number <= 'f') return number - 'a' + 0x0a;
  else return 0;
}

3. corrected ternary operator version that handles also capital letter inputs, proposed by g24l:

long long hextoint(char in) {
  int const x = in;
  return (x <= 57)? x - 48 : (x <= 70)? (x - 65) + 0x0a : (x - 97) + 0x0a;
}

4. lookup table (unordered_map):

long long hextoint(char number) {
  return table[(std::size_t)number];
}

where table is the unordered map shown previously.

5. lookup table (user constexpr literal):

long long hextoint(char number) {
  return table[(std::size_t)number];
}

where table is user defined literal as shown above.

experimental settings

i defined a function that transforms an input hex string to an integer:

long long hexstrtoint(std::string const &str, long long(*f)(char)) {
  long long ret = 0;
  for(int j(1), i(str.size() - 1); i >= 0; --i, j *= 16) {
    ret += (j * f(str[i]));
  }
  return ret;
}

i also defined a function that populates a vector of strings with random hex strings:

std::vector<std::string>
populate_vec(int const n) {
  random_device rd;
  mt19937 eng{ rd() };
  uniform_int_distribution<long long> distr(0, std::numeric_limits<long long>::max() - 1);
  std::vector<std::string> out(n);
  for(int i(0); i < n; ++i) {
    out[i] = int_to_hex(distr(eng));
  }
  return out;
}

i created vectors populated with 50000, 100000, 150000, 200000 and 250000 random hex strings respectively. then for each algorithm i run 100 experiments and averaged the time results.

compiler was gcc version 5.2 with optimization option -o3.

results:

discussion

from the results we can conclude that for these experimental settings the proposed table method out-performs all the other methods. the if-else method is by far the worst where as the unordered_map although it wins the if-else method it is significantly slower than the other proposed methods.

code

edit:

results for method proposed by stgatilov, with bitwise operations:

long long hextoint(char x) {
    int b = uint8_t(x);
    int maskletter = (('9' - b) >> 31);
    int masksmall = (('z' - b) >> 31);
    int offset = '0' + (maskletter & int('a' - '0' - 10)) + (masksmall & int('a' - 'a'));
    return b - offset;
}

edit:

i also tested the original code from g24l against the table method:

long long hextoint(char in) {
  long long const x = in;
  return x < 58? x - 48 : x - 87;
}

note that this method doesn't handle capital letters a, b, c, d, e and f.

results:

still the table method renders faster.

By chamberlainpi on January 15 2022

Answers related to “what's the fastest way to convert hex to integer in c++?”

Only authorized users can answer the Search term. Please sign in first, or register a free account.