%g 浮点数表示的最大字符串长度是多少?

What is the maximum string length for %g float representation?

提问人:Abdulmalek Almkainzi 提问时间:9/25/2023 最后编辑:Abdulmalek Almkainzi 更新时间:9/25/2023 访问量:122

问:

堆栈分配的字符串需要多大才能以 %g 格式存储任何浮点数/双精度?

int main()
{
    float f;
    double d;
    
    char f_str[ ?? ];
    char d_str[ ?? ];
    
    sprintf(f_str, "%g",  f);
    sprintf(d_str, "%lg", d);
}

编辑:

我希望在编译时知道字符串大小,这样我就不依赖于堆分配或 VLA

C 字符串 浮点 printf

评论

1赞 500 - Internal Server Error 9/25/2023
这回答了你的问题吗?表示任何双精度值所需的最大字符长度是多少?
2赞 Chris 9/25/2023
你确定你没有过度优化吗?你说的是几个字节。
1赞 dbush 9/25/2023
@AbdulmalekAlmkainzi 如果您没有明确给出精度,它将打印多达 6 位有效数字。然后,您需要为可能的减号加上任何指数说明符添加空间,即 .-1e+5
1赞 Ted Lyngmo 9/25/2023
我想知道是否还有比 和 更长的字符串?常见的值(但不是一成不变的)是 (13 个字符)、(14 个字符) 和 (15 个字符)。-FLT_MAX-DBL_MAX-LDBL_MAX-3.40282e+38-1.79769e+308-1.18973e+4932
1赞 ikegami 9/25/2023
@500 - 内部服务器错误,否,因为不会打印所有数字。%g

答:

3赞 pmg 9/25/2023 #1

您可以使用 snprintf() 来计算特定格式字符串和值所需的确切长度

float f = 3.14159265358979;
int f_len = snprintf(NULL, 0, "%g", f);
char f_str[f_len + 1]; // or malloc...
sprintf(f_str, "%g", f); // it fits
// remember to free if you malloc'd before

评论

0赞 Abdulmalek Almkainzi 9/25/2023
但现在是一个运行时值,使 VLAf_lenf_str
1赞 pmg 9/25/2023
这是正确的@AbdulmalekAlmkainzi。在这种特殊情况下,字符串不会大到足以成为潜在问题。
1赞 chux - Reinstate Monica 9/25/2023 #2

%g 浮点数表示的最大字符串长度是多少?

当值在 10+/- 999 以内时为 13

15 与二进制128


对于极值,使用指数表示法。"%g"

"%g",缺少宽度或精度,将打印 6 位有效数字。

长期预期形式:

[sign][digit].[5 digits]e[sign][expo_digits]
   1     1   1    5     1   1       3        --> 13

例:

//           1234567890123
DBL_TRUE_MIN -4.94066e-324

  • 当具有更宽的指数范围时,需要额外的空间。double

  • NAN 可能会打印更长的内容。很多都是实现定义的。一个合理的最坏情况形式会将其估计为“-sNAN”十进制有效载荷“ binary64 的有效载荷可能是小数点后 16 位。


堆栈分配的字符串需要多大才能以 %g 格式存储任何浮点数/双精度?

如果寻求一个常数,给定指数范围(以十进制表示)可能超过 3 位,并且 NAN 可能会打印有效负载,我会在 NAN 有效负载打印上进行缩放,因为这肯定是最坏的情况。使用以位为单位的有效大小,通过按 log10(2) 缩放来确定十进制有效负载。

#define DBL_SIZE (sizeof(double)*CHAR_BIT)
#define LOG10_2_NUM 302
#define LOG10_2_DEN 1000
#define DBL_PAYLOAD (DBL_MANT_DIG*LOG10_2_NUM/LOG10_2_DEN)
#define DBL_G_SIZE (5 /* -sNAN */ + DBL_PAYLOAD + 1 /* \0 */ )

因此,对于普通 .double


鉴于所有潜在的实现定义属性,我会使用 .snprintf()

 char buf[DBL_G_SIZE];
 int len = snprintf(buf, sizeof buf, "%g", x);
 assert(len > 0 && (unsigned) len < sizeof buf);

评论

0赞 chux - Reinstate Monica 9/25/2023
我想应该是.会沉思。#define DBL_PAYLOAD (DBL_MANT_DIG*LOG10_2_NUM/LOG10_2_DEN)... DBL_MANT_DIG*LOG10_2_NUM/LOG10_2_DEN + 1)
0赞 Abdulmalek Almkainzi 9/25/2023
假设 IEEE-754 标准。浮点数的缓冲区大小为 13 + 1,双精度值的缓冲区大小为 21 + 1,足以表示格式中的任何值,对吗?%g
1赞 chux - Reinstate Monica 9/25/2023
@AbdulmalekAlmkainzi 这些尺寸是合理的。如果使用 ,则几乎没有缺点。关键是,在这种情况下,我们不应该吝啬。char buf[DBL_G_SIZE * 2];
2赞 vinc17 9/25/2023 #3

这取决于实际的浮点格式和当前区域设置,因为某些字符(如小数点字符)可能需要几个字节。例如,如果对应于 IEEE 754 binary64 格式(又名双精度),则在 C 语言环境中,最大字符串长度(以字节数表示)为 13,但实际上可能是 14(我什至不认为 C 标准有限制)。double

例:

#include <stdio.h>
#include <float.h>
#include <string.h>
#include <locale.h>

static void f (void)
{
  char s[256];
  double x = -DBL_MAX;
  printf ("%g\n", x);
  sprintf (s, "%g", x);
  printf ("%zu\n", strlen (s));
}

int main (void)
{
  f ();
  setlocale (LC_ALL, "ps_AF");
  f ();
  return 0;
}

在我的 Debian Linux 机器上(其中启用了所有语言环境),我得到:

-1.79769e+308
13
-1٫79769e+308
14

14 是由于 U+066B 阿拉伯十进制分隔符用于ps_AF区域设置(基于 UTF-8)中的小数点字符,编码为 D9 AB。

答案与 类似,但您需要知道相关格式的最小和最大指数。long double