18 апр. 2013 г., 01:05 отarsaKasraShailesh Tainwala

Преобразование double в char * в C ++ с высокой производительностью

оему приложению необходимо преобразовать двойные значения в char * для записи в канал, который принимает только символы. Обычные способы сделать это с помощьюsprintf () функция или использование Ostringstream из заголовочного файла iomanip.h.

Оказывается, у обоих очень плохая производительность. И моему приложению нужно делать это преобразование так часто, что оно становится основным узким местом.

Есть ли другая функция, которую я мог бы использовать? Какую логику я могу использовать, чтобы написать эффективную функцию преобразования? Единственное, что мне удалось до сих пор придумать, - это вывести каждую отдельную цифру, используя операции деления и мода, и добавить эти цифры к символу *, чтобы получить все двойное значение. Это не похоже на хороший подход, и, скорее всего, будет иметь плохую производительность.

Заранее спасибо за ваши мысли.

EDIT: есть некоторая путаница по поводу того, как будет использоваться char *. Char * будет аргументом функции fwrite, которая пишет в канал.

Ответы на вопрос(8)

25 мая 2012 г., 11:01 отSibren
/*

_ecvt_s Converts a double number to a string.

Syntax:

errno_t _ecvt_s( 
   char * _Buffer,
   size_t _SizeInBytes,
   double _Value,
   int _Count,
   int *_Dec,
   int *_Sign
);

[out] _Buffer
Filled with the pointer to the string of digits, the result of the conversion.

[in] _SizeInBytes
Size of the buffer in bytes.

[in] _Value
Number to be converted.

[in] _Count
Number of digits stored.

[out] _Dec
Stored decimal-point position.

[out] _Sign
Sign of the converted number.


*/


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

...
char *buf = (char*) malloc(_CVTBUFSIZE);
int decimal;
int sign;
int err;


err = _ecvt_s(buf, _CVTBUFSIZE, 1.2, 5, &decimal, &sign);

if (err != 0) {
// implement error handling
}
else printf("Converted value: %s\n", buf);

...

25 мая 2012 г., 05:45 отSaad

если вы хотите читать данные побайтно. использовать эту технику

double dbl = 2222;
char* ptr = (char*)(&dbl);

это вернет младший байт dbl. и ptr ++ будет ссылаться на 2-й байт dbl.

25 мая 2012 г., 05:46 отTony Delroy

dtostre а такжеdtostrfункции преобразования @ - возможно, стоит сравнить. Вы можете посмотреть наsprintf() исходный код (например, версия GNU) для идей, подбирая%e, %f и / или%g форматирование по желанию, избегая шага интерпретации форматной строки и даже делая его встраиваемым, и настройку производительности по вкусу - вы можете удалить специальный регистр для NaN, бесконечности и других значений, если знаете, что вам не нужно обрабатывать их .

25 мая 2012 г., 05:48 отCommunity

которое может поддерживать двойной тип, используйте любую библиотеку для выполнения этой работы. Это сохраняет ваше здравомыслие: Почему "dtoa.c" содержит так много кода?

Если вы хотите напечатать подмножество чисел двойным шрифтом. Например, до 4 цифр после десятичной точки и не более 5 цифр до десятичной точки, затем вы можете округлить число и преобразовать его в тип int, прежде чем выводить его на печать с использованием подразделения и мода. Я могу подтвердить эффективность этого метода.

РЕДАКТИРОВАТЬ Если исходной целью является отправка данных для связи, то отправка двоичной формы double будет самым быстрым и точным способом (без возможной потери точности из-за преобразования). Способ сделать это объясняется в других ответах.

25 мая 2012 г., 05:53 отCasey

Вы можете использовать std :: ostreamwrite and std :: istreamread методы с любым типом данных, вам просто нужно переинтерпретировать данные в виде указателя на символ:

double value = 5.0;
std::ostream os;
//...
os.write(reinterpret_cast<const char*>(&value), sizeof(value));
//..
std::istream is;
is.read(reinterpret_cast<char*>(&value), sizeof(value));
25 мая 2012 г., 12:09 отCommunity

воение или вам нужно правильное текстовое представление двойника?

Если вы просто туннелируете, а канал очищен на 8 бит, используйте один из ответов выше.

Если вам нужна строка, используйте один из ответов выше.

Если ваша проблема в том, что ширина канала всего 7 бит, то преобразуйте вradix 64 при записи и обратно при чтении.

25 мая 2012 г., 06:00 отJirka Hanika

sprintf в вашей системе не обязательно конвертирует double, но анализирует строку формата. Это может быть хорошей новостью для вас, поскольку это то, что вы могли бы оптимизировать.

Кроме того, старайтесь задокументировать все ваши знания о дальности, точности и характереdouble значения, которые нужно обработать, и использовать его для разработки специального алгоритма.

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

itoa((int)((f + 0.00001) * 10000))

Однакоsprintf а такжеostream подходы, о которых вы уже знаете, являются единственными решениями, которые носят общий и переносимый характер.

25 мая 2012 г., 05:50 отCommunity

ftoa будет немного лучше, чемsprintf поскольку это то, что он использует внутри. Смотрите связанный вопросВо Также посмотрите, как ftoa реализован в исходном коде вашей библиотеки, и посмотрите, сможете ли вы улучшить его для ваших конкретных сценариев.

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

ВАШ ОТВЕТ НА ВОПРОС