在 C++ 中以高性能将 double 转换为 char*
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10749585/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Converting double to char* in C++ with high performance
提问by Shailesh Tainwala
My application needs to convert double values to char* to write to a pipe that accepts only characters. The usual ways of doing this are using the sprintf()function or using ostringstreamfrom iomanip.h header file.
我的应用程序需要将 double 值转换为 char* 以写入仅接受字符的管道。执行此操作的常用方法是使用sprintf()函数或使用iomanip.h 头文件中的ostringstream。
Turns out, both of these have really bad performance. And my application needs to do this conversion so often that it becomes the primary bottleneck.
事实证明,这两者的性能都非常糟糕。而且我的应用程序需要经常进行这种转换,以至于它成为主要瓶颈。
Is there any other function I could use? What logic can I use to write an efficient conversion function? The only thing I have managed to come up with so far is to get each individual digit out using division and mod operations, and append these digits to a char* to get the entire double value. This doesn't seem like a good approach though, and will likely have bad performance itself.
我可以使用其他任何功能吗?我可以使用什么逻辑来编写高效的转换函数?到目前为止,我设法想出的唯一一件事是使用除法和 mod 操作获取每个单独的数字,并将这些数字附加到 char* 以获取整个双精度值。但这似乎不是一个好方法,并且本身可能会产生糟糕的性能。
Thanks in advance for your thoughts.
预先感谢您的想法。
EDIT: There is some confusion over how the char* will be used. The char* will be an argument to the fwrite function which writes to a pipe.
编辑:关于如何使用 char* 存在一些混淆。char* 将是写入管道的 fwrite 函数的参数。
采纳答案by nhahtdh
If you want to print any number that double type can support, use whatever library out there to do the job. It saves your sanity: Why does "dtoa.c" contain so much code?
如果您想打印双精度型可以支持的任何数字,请使用任何库来完成这项工作。它可以让您保持理智:为什么“dtoa.c”包含这么多代码?
If you want to print a subset of numbers in double type. For example, up to 4 digits after decimal point, and not more than 5 digits before decimal point, then you can round the number and convert to int type, before printing it out using division and mod. I can confirm the performance of this method.
如果要以 double 类型打印数字的子集。例如,小数点后最多4位,小数点前不超过5位,然后可以将数字四舍五入并转换为int类型,然后使用除法和mod打印出来。我可以确认这种方法的性能。
EDIT:If you original purpose is to send the data for communication, then sending the binary form of double will be the fastest and most accurate method (no possible loss of precision due to conversion). The way to do this is explained in other answers.
编辑:如果您最初的目的是发送数据进行通信,那么发送 double 的二进制形式将是最快和最准确的方法(不会因转换而损失精度)。其他答案中解释了这样做的方法。
回答by Casey
You can use the std::ostream write
and std::istream read
methods with any data type you just have to reinterpret_cast the data as a char pointer:
您可以将 std::ostreamwrite
和 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));
回答by Saad
if you wanna read data byte by byte. use this technique
如果你想逐字节读取数据。使用这种技术
double dbl = 2222;
char* ptr = (char*)(&dbl);
this will return lowest byte of dbl. and ptr++ will refer 2nd byte of dbl.
这将返回 dbl 的最低字节。和 ptr++ 将引用 dbl 的第二个字节。
回答by Julian
Are you in control of both ends of the pipe? Are you just trying to tunnel doubles through or do you need a valid text representation of the double?
你能控制管道的两端吗?您只是想通过隧道传送双打,还是需要双打的有效文本表示?
If you are just tunneling and the pipe is 8 bit clean then use one of the answers above.
如果您只是在挖隧道并且管道是 8 位干净的,那么请使用上面的答案之一。
If you need a string use one of the other answers above.
如果您需要字符串,请使用上面的其他答案之一。
If your problem is that the pipe is only 7 bits wide, then convert to radix 64on write and back again on read.
如果您的问题是管道只有 7 位宽,则在写入时转换为基数 64,并在读取时再次返回。
回答by Jirka Hanika
The slow part of sprintf
on your system may not necessarily be converting the double, but parsing the format string. That might be good news for you as that is something that you could optimize away.
系统上较慢的部分sprintf
可能不一定是转换双精度数,而是解析格式字符串。这对您来说可能是个好消息,因为这是您可以优化的东西。
Additionally, try hard to document all the knowledge you have about range, accuracy, and nature of the double
values that you need to process, and use it to develop a special algorithm.
此外,努力记录您对double
需要处理的值的范围、准确性和性质的所有知识,并使用它来开发特殊算法。
Assuming your inputs are never subnormal numbers, use a known fixed precision and accuracy, a relatively high performing result may look like this:
假设您的输入永远不是次正规数,使用已知的固定精度和准确度,性能相对较高的结果可能如下所示:
itoa((int)((f + 0.00001) * 10000))
However, the sprintf
and ostream
approaches you are already aware of are the only solutions that are completely general and portable.
但是,您已经知道的sprintf
和ostream
方法是唯一完全通用且可移植的解决方案。
回答by Dragos
/*
_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);
...
Hope this helps.
希望这可以帮助。
回答by Tony Delroy
Some systems provide dtostre
and dtostrf
conversion functions - might be worth benchmarking. You can look at sprintf()
source code (e.g. GNU version) for ideas, picking up the %e
, %f
and/or %g
formatting as desired, avoiding the format string interpretation step and even making it inlinable, and performance-tune to taste - you might be able to remove special casing for NaN, infinity and other values if you know you don't have to handle them.
一些系统提供dtostre
和dtostrf
转换功能 - 可能值得进行基准测试。你可以看一下sprintf()
源代码(如GNU版本)的想法,拿起%e
,%f
和/或%g
格式化的需要,避免了格式字符串解释一步,甚至使其可以内联,以及性能调口味-你可能能够删除NaN、无穷大和其他值的特殊大小写,如果你知道你不必处理它们。
回答by SmacL
Using ftoa
will be slightly better than sprintf
as this is what it is using internally. See related question hereAlso look at how ftoa is implemented in your library source and see if you can improve on it for your specific scenarios.
使用ftoa
会比sprintf
它在内部使用的要好一些。请参阅此处的相关问题 另请查看如何在您的库源中实现 ftoa,并查看您是否可以针对您的特定场景对其进行改进。
It seems ftoa
is not standard at all, my bad. Here's a discussion showing an implementationwhich claims to be far faster that sprintf. You'd need to profile both on your own target environments, and implement with double rather than float.
这似乎ftoa
根本不标准,我的错。这是一个讨论,展示了一个声称比 sprintf 快得多的实现。您需要在自己的目标环境中对两者进行分析,并使用 double 而不是 float 实现。