Как более эффективно пройти массив символов, хранящий {int, short, ushort, ...}? - PullRequest
0 голосов
/ 17 ноября 2011

У меня есть char data[len] заполненный из разархивированных данных, которые считываются из двоичного файла. Я знаю, что data может быть только следующих типов: char, uchar, short, ushort, int, uint, float, double, для которого я знаю точное количество бит, необходимое для представления (elesize = {8, 16, 32, 64}).

Я просто хочу просмотреть список данных и, скажем, найти max(), min() или количество вхождений данного числа. и я хочу сделать это, не создавая другой массив для проблем с памятью.

Я придумал следующее, но это медленно, например, для len == 34560000

Так что мне было интересно, есть ли у кого-нибудь «однострочный» или более эффективный способ сделать это (C или C ++).

char data[len];
double mymax = -std::numeric_limits<double>::max()
for (size_t i=0; i<len; i += elesize)
{
    double x;
    char *r = data+i;
    if (elementtype == "char")
        x = static_cast<double>(*r);
    else if (elementtype == "uchar")
        x = static_cast<double>(*((unsigned char *)r));
    else if (elementtype == "short")
        x = static_cast<double>(*((int16_t *)r));
    else if (elementtype == "ushort")
        x = static_cast<double>(*((uint16_t *)r));
    else if (elementtype == "int")
        x = static_cast<double>(*((int32_t *)r));
    else if (elementtype == "uint")
        x = static_cast<double>(*((uint32_t *)r));
    else if (elementtype == "float")
        x = static_cast<double>(*((float *)r));
    else if (elementtype == "double")
        x = *((double *)r);
    if (x > mymax)
        mymax = x;
}

Ответы [ 4 ]

1 голос
/ 18 ноября 2011

Шаблон должен хорошо работать:

#include <algorithm>

template <typename T>
T read_and_advance(const unsigned char * & p)
{
  T x;
  unsigned char * const px = reinterpret_cast<unsigned char *>(&x);

  std::copy(p, p + sizeof(T), px);
  P += sizeof(T);

  return x;
}

Использование:

const unsigned char * p = the_data;
unsigned int max = 0;

while (p != the_data + data_length)
{
  max = std::max(max, read_and_advance<unsigned int>(p));
}

Отбрось это, я думал, первоначально вопрос был для C.

Вот макрос:

#define READ_TYPE(T, buf, res) do { memcpy(&res, buf, sizeof(T)); buf += sizeof(T); } while (false)

Использование:

int max = 0;
unsigned char * p = data;

while (true)
{
  unsigned int res;
  READ_TYPE(unsigned int, p, res);
  if (res > max) max = res;
}

На самом деле вы не можете обойтись без указания типа , хотя.В C ++ это можно сделать немного более элегантно.

В качестве альтернативы вы можете обернуть все это в один:

#define READ_TYPE_AND_MAX(T, buf, max)  \
  do { T x; memcpy(&x, buf, sizeof(T)); \
       buf += sizeof(T);                \
       if (max < x) max = x;            \
  } while (false)

// Usage:
unsigned int max = 0;
unsigned char * p = data;
while (true) { READ_TYPE_AND_MAX(unsigned int, p, max); }

0 голосов
/ 18 ноября 2011

Как указали другие, вы должны проверять тип только один раз. Затем вы должны вызвать соответствующую подфункцию, которая работает только с одним типом. Вы также не должны приводить к двойникам для сравнения с my_max, когда тип элемента не является двойным. В противном случае вы без необходимости конвертируетесь в удвоения и сравниваете с двойниками. Если elementtype имеет тип uint, то вы никогда не должны преобразовывать что-либо в удвоение, просто сравните с переменной my_max, которая также является uint.

0 голосов
/ 17 ноября 2011

Поместите условный код вне цикла, чтобы цикл работал быстро. Попробуйте что-то вроде этого:

char data[len];
double mymax = -std::numeric_limits<double>::max()
double x;
if (elementtype == "char") {
  for (size_t i=0; i<len; i += elesize) {
    char *r = data+i;
    x = static_cast<double>(*r);
    if (x > mymax)  mymax = x;
  }
}else if (elementtype == "uchar") {
  for (size_t i=0; i<len; i += elesize) {
    char *r = data+i;
    x = static_cast<double>(*((unsigned char *)r));
    if (x > mymax)  mymax = x;
  }
}else if (elementtype == "short")

..etc..etc
0 голосов
/ 17 ноября 2011

Учитывая, что elementtype является инвариантным к циклу, лучше выполнить сравнение только один раз за пределами for. Кстати, я надеюсь, что elementtype имеет тип std::string или что-то, что многозначительно сравнивается со строковыми литералами.

В конечном итоге я написал бы функцию шаблона, которая выполняет весь цикл обработки, а затем вызвал бы ее с подходящим аргументом шаблона в соответствии с elementtype.

...