Приведение массива неподписанных символов к массиву с плавающей точкой - PullRequest
6 голосов
/ 05 мая 2009

Каков наилучший способ преобразования массива без знака в массив с плавающей точкой в ​​c ++?

В настоящее время у меня есть цикл for следующим образом

for (i=0 ;i< len; i++)
    float_buff[i]= (float) char_buff[i];

Мне также нужно изменить процедуру, т. Е. Преобразовать из unsigned char в float (с плавающей точкой в ​​8-битное преобразование)

for (i=0 ;i< len; i++)
    char_buff[i]= (unsigned char) float_buff[i];

Буду признателен за любой совет

Спасибо

Ответы [ 8 ]

9 голосов
/ 05 мая 2009

Я думаю, что лучше всего использовать функциональный объект:

template <typename T> // T models Any
struct static_cast_func
{
  template <typename T1> // T1 models type statically convertible to T
  T operator()(const T1& x) const { return static_cast<T>(x); }
};

с последующим:

std::transform(char_buff, char_buff + len, float_buff, static_cast_func<float>());
std::transform(float_buff, float_buff + len, char_buff, static_cast_func<unsigned char>());

Это наиболее читаемый текст, потому что он говорит о том, что делается на английском языке: преобразование последовательности в другой тип с использованием статического приведения. А будущие приведения могут быть сделаны в одну строку.

8 голосов
/ 05 мая 2009

Ваше решение в значительной степени лучший вариант, однако я бы подумал о переходе на:

char_buff[i]= static_cast<unsigned char>(float_buff[i]);
2 голосов
/ 05 мая 2009

Ваш первый цикл не требует приведения. Вы можете неявно конвертировать из одного типа (например, unsigned char) в более широкий тип (например, float). Ваш второй цикл должен использовать static_cast:

for (i=0; i< len; i++)
    char_buff[i]= static_cast<unsigned char>(float_buff[i]);

Мы используем static_cast, чтобы явно указать компилятору выполнить преобразование в более узкий тип. Если вы не используете приведение, ваш компилятор может предупредить вас, что преобразование может потерять данные. Присутствие оператора приведения означает, что вы понимаете, что можете потерять точность данных, и с этим все в порядке. Это не подходящее место для использования reinterpret_cast. С static_cast вы, по крайней мере, имеете некоторые ограничения на то, какие преобразования вы можете делать (например, это, вероятно, не позволит вам преобразовать Bird* в Nuclear_Submarine*). reinterpret_cast не имеет таких ограничений.

Кроме того, вот что Бьярн Страуструп должен сказать по этому вопросу.

2 голосов
/ 05 мая 2009

С какой целью вы это делаете? Вставить поплавок в полукокса не имеет смысла. На большинстве платформ число с плавающей запятой будет 4 байта и представляет число с плавающей запятой, где как символ будет 1 байт и часто представляет один символ. Вы потеряете 3 байта данных, пытаясь засунуть float в символ, верно?

2 голосов
/ 05 мая 2009

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

1 голос
/ 05 мая 2009

Приведение происходит автоматически, поэтому вам не нужно указывать его явно.
Но вы можете использовать стандартные алгоритмы:

std::copy(char_buff,char_buff+len,float_buff);

Преобразование обратно из числа с плавающей запятой в потенциальную потерю информации. Так что вам нужно быть более явным.

std::transform(float_buff,float_buff+len,char_buff,MyTransform());

Здесь мы используем класс MyTransform, который должен иметь оператор (), который принимает число с плавающей запятой и возвращает символ. Это должно быть тривиально для импликации.

0 голосов
/ 05 мая 2009

Никто не упомянул об этом, но если вы выполняете какую-либо арифметику с плавающей точкой, вы можете округлить вместо усечения ... если у вас есть символ 49, и после некоторой арифметики он превращается в 4.9E1 , он может превратиться в 4.89999999E1, который превратится в 48, когда вы превратите его обратно в символ.

Если вы ничего не делаете с поплавком, это не должно быть проблемой, но тогда зачем вам это нужно как поплавок?

0 голосов
/ 05 мая 2009

Если вы имеете дело с очень большими массивами и производительность важна, то следующее может оказаться несколько более эффективным:

   float *dst = float_buff;
   unsigned char *src = char_buff;

   for (i=0; i<len; i++) *dst++ = (float)*src++;
...