sprintf(buf, "%.20g", x) // buf 应该有多大?
我将双精度值转换为字符串,如下所示:
std::string conv(double x) {
char buf[30];
sprintf(buf, "%.20g", x);
return buf;
}
我已将缓冲区大小硬编码为 30,但不确定这对于所有情况是否足够大。
- 如何找出我需要的最大缓冲区大小?
- 从 32 位切换到 64 时,精度是否会变得更高(因此缓冲区需要增加)?
PS:出于性能原因,我无法使用 ostringstream
或 boost::lexical_cast
(请参阅这个)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是。 %.20g 指定尾数中的 20 位数字。小数点加 1。 1 表示(可能的)符号,5 表示“e+308”或“e-308”,最坏情况下的指数。 1 表示终止 null。
20 + 1 + 1 + 5 + 1 = 28。
不会。
两种架构中的 double 大小相同。如果将变量声明为 long double,则指数“e+4092”中可能会多出 1 个数字,该数字仍然适合 30 个字符的缓冲区。但仅适用于 X86,且仅适用于较旧的处理器。
long double 是一种过时的 80 位浮点值形式,是 486 FPU 的本机格式。该 FPU 架构扩展性不佳,因此被放弃,取而代之的是 SSE 风格指令,其中最大可能的浮点值是 64 位双精度。
从长远来看,只要您将打印输出中的尾数限制为 20 位,30 个字符的缓冲区就始终足够。
It is. %.20g specifies 20 digits in the mantissa. add 1 for decimal point. 1 for (possible) sign, 5 for "e+308" or "e-308", the worse case exponent. and 1 for terminating null.
20 + 1 + 1 + 5 + 1 = 28.
No.
A double is the same size in both architectures. If you declare your variables as long double, then you possibly have 1 more digit in the exponent "e+4092", which still fits in a 30 character buffer. But only on X86, and only on older processors.
The long double is an obsolete 80 bit form of floating point value that was the native format of the 486 FPU. That FPU architecture didn't scale well and as since been discarded in favor of SSE style instructions where the largest possible floating point value is a 64 bit double.
Which is a long way of saying a buffer of 30 characters will always be sufficient as long as you keep limiting the mantissa in your printout to 20 digits.
printf("%.20g", 1.79769e+308);
是1.7976900000000000632e+308
,27 个字节,包括结尾的 \0。为了确定起见,我会选择 64 或 128。(因为它位于堆栈上并在您也可以使用大缓冲区(甚至 2048 字节)后立即释放,而不会遇到非嵌入式应用程序的问题)
另外,您确定程序的瓶颈是 lexical_cast 吗..?做你正在做的事情对我来说似乎很愚蠢
printf("%.20g", 1.79769e+308);
is1.7976900000000000632e+308
, 27 bytes including the trailing \0. I would choose 64 or 128 just to be sure.(Since it's on the stack and released right after you could also go with big buffers, even 2048 bytes, without running into problems for non embedded applications)
Also, are you sure the bottleneck of your program is
lexical_cast
..? Doing what you're doing seems very silly to me我似乎记得,如果您使用
NULL
目的地调用sprintf
,它不会执行任何操作。但是,它确实返回它“写入”的字符数。如果我是对的(而且我似乎找不到来源),那么您可以这样做:另一个选择是使用
snprintf
它允许您限制输出的长度:snprintf
将缓冲区的大小作为参数,并且不允许输出字符串超过该大小。I seem to remember that if you call
sprintf
with aNULL
destination, it doesn't do anything. It does, however, return the number of chars that it "wrote". If I'm right (and I can't seem to find the source for that) then you can do:Another option is to use
snprintf
which allows you to limit the length of the output:snprintf
takes the size of the buffer as an argument, and doesn't allow the output string to exceed that size.这是一个程序,用于打印任何系统中
double
可以采用的最大和最小值所需的位数:对我来说,它打印:
由于 27 包含换行符,但不包含终止
0
对于字符串,我想说在这个系统上,27 就足够了。对于long double
,在我的系统上,LDBL_MAX
和LDBL_MIN
的答案似乎分别是 27 和 28。手册页(在我的
sprintf
上)这样描述了%g
:C 标准中也有类似的措辞。
因此,我认为如果您使用上述程序的输出作为数组大小,您将是安全的。
Here's a program to print the number of digits required for maximum and minimum values
double
can take for any system:For me, it prints:
Since 27 includes a newline but doesn't include the terminating
0
for the strings, I would say that on this system, 27 should suffice. Forlong double
, the answer seems to be 27 and 28 forLDBL_MAX
andLDBL_MIN
respectively on my system.The man page (on my for
sprintf
says this about%g
:Similar wording is in the C standard.
So I think you will be safe if you used the output from the above program as your array size.
如果您使用的平台支持 POSIX 或 C99,则应该能够使用
snprintf
来计算您需要的缓冲区的大小。snprintf
接受一个参数,指示您传入的缓冲区的大小;如果字符串的大小超过该缓冲区的大小,它会截断输出以适合缓冲区,并返回适合整个输出所需的空间量。您可以使用它的输出来分配大小正确的缓冲区。如果您只想计算所需的缓冲区大小,则可以传入 NULL 作为缓冲区和大小 0 来计算需要多少空间。使用后请记住
free(buf)
以避免内存泄漏。这样做的问题是它无法在 Visual Studio 中运行,它仍然不支持 C99。虽然他们有 类似
snprintf
,如果传入的缓冲区太小,它不会返回需要的大小,而是返回-1
,这是完全没有用的(并且它不接受NULL< /code> 作为缓冲区,即使长度为
0
)。如果您不介意截断,则可以简单地将
snprintf
与固定大小的缓冲区一起使用,并确保不会溢出它:请确保在
snprintf< 上检查您的平台文档/代码>;特别是,如果字符串被截断,某些平台可能不会在字符串末尾添加终止 null,因此您可能需要自己执行此操作。
If you are on a platform that supports POSIX or C99, you should be able to use
snprintf
to compute the size of the buffer you will need.snprintf
takes a parameter indicating the size of the buffer you are passing in; if the size of the string would exceed the size of that buffer, it truncates the output to fit into the buffer, and returns the amount of space it would have needed to fit the entire output. You can use the output of this to allocate a buffer that's the exact right size. If you just want to compute the size of the buffer you need, you can pass in NULL as the buffer and a size of 0 to compute how much space you need.Remember to
free(buf)
after you've used it to avoid memory leaks.The problem with this is that it won't work in Visual Studio, which still does not support C99. While they have something like
snprintf
, if the buffer passed in is too small, it does not return the size needed, but returns-1
instead, which is completely useless (and it does not acceptNULL
as a buffer, even with a0
length).If you don't mind truncating, you can simply use
snprintf
with a fixed size buffer, and be assured that you won't overflow it:Make sure you check your platform docs on
snprintf
; in particular, some platforms may not add a terminating null at the end of the string if the string is truncated, so you may need to do that yourself.