在C ++中以高性能将double转换为char *

时间:2012-05-25 06:32:25

标签: c++ performance type-conversion

我的应用程序需要将double值转换为char *以写入仅接受字符的管道。通常的方法是使用 sprintf()函数或使用iomanip.h头文件中的 ostringstream

事实证明,这两者都有非常糟糕的表现。我的应用程序需要经常进行这种转换,以至于它成为主要的瓶颈。

我还可以使用其他功能吗?我可以使用什么逻辑来编写有效的转换函数?到目前为止,我唯一想到的就是使用除法和修改操作来获取每个数字,并将这些数字附加到char *以获得整个double值。这似乎不是一个好方法,并且本身可能会有糟糕的表现。

提前感谢您的想法。

编辑:关于如何使用char *存在一些混淆。 char *将是写入管道的fwrite函数的参数。

8 个答案:

答案 0 :(得分:17)

如果要打印双重类型可以支持的任何数字,请使用其中的任何库来完成工作。它可以节省您的理智:Why does "dtoa.c" contain so much code?

如果要以double类型打印数字子集。例如,小数点后最多4位数,小数点前不超过5位数,那么你可以使用除法和mod打印出来之前将数字舍入并转换为int类型。我可以确认这种方法的性能。


修改 如果您的原始目的是发送数据进行通信,那么发送二进制形式的double将是最快和最准确的方法(由于转换不会丢失精度)。其他答案中解释了执行此操作的方法。

答案 1 :(得分:9)

您可以将std :: ostream write和std :: istream read方法与任何数据类型一起使用,将数据重新解释为一个char指针:

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));

答案 2 :(得分:7)

如果你想逐字节读取数据。使用这种技术

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

这将返回dbl的最低字节。和ptr ++将引用dbl的第二个字节。

答案 3 :(得分:3)

你是否控制了管道的两端?你只是试图通过隧道双打,还是需要双重的有效文本表示?

如果您只是隧道并且管道是8位清洁,那么请使用上面的答案之一。

如果您需要字符串,请使用上述其他答案之一。

如果你的问题是管道只有7位宽,那么在写入时转换为radix 64,在读取时再转换回来。

答案 4 :(得分:2)

某些系统提供dtostredtostrf转换功能 - 可能值得进行基准测试。您可以查看sprintf()源代码(例如GNU版本)以获取提示,根据需要选择%e%f和/或%g格式,避免格式字符串解释步骤,甚至使它无法使用,并且性能调整到味道 - 如果你知道你不需要处理它们,你可能能够移除NaN,无穷大和其他值的特殊外壳。

答案 5 :(得分:2)

系统上sprintf的缓慢部分可能不一定是转换double,而是解析格式字符串。这对你来说可能是个好消息,因为那是你可以优化的东西。

此外,请尽量记录您需要处理的double值的范围,准确性和性质的所有知识,并使用它来开发特殊算法。

假设您的输入从不是次正规数,请使用已知的固定精度和准确度,相对较高的结果可能如下所示:

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

但是,您已经知道的sprintfostream方法是唯一完全通用且可移植的解决方案。

答案 6 :(得分:2)

/*

_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);

...

希望这有帮助。

答案 7 :(得分:1)

使用ftoa会比sprintf略好,因为这是它在内部使用的内容。请参阅相关问题here另请参阅如何在您的图书馆资源中实施ftoa,看看您是否可以针对特定情况对其进行改进。

似乎ftoa根本不是标准,我的不好。这是discussion showing an implementation声称比sprintf快得多。您需要在自己的目标环境中对两者进行分析,并使用double而不是float来实现。