是否有一个printf宽度的说明符可以应用于浮点说明符,该说明符会自动将输出格式化为所需的significant digits数字,以便在扫描回字符串时获取原始浮点值?

例如,假设我将float打印为小数点后2位的精度:

float foobar = 0.9375;
printf("%.2f", foobar);    // prints out 0.94

当我扫描输出0.94时,我没有符合标准的保证,我将获得原始的0.9375浮点值(在本例中,我可能不会).

我想知道一种方法,告诉printf自动打印浮点值到所需的数字significant digits,以确保它可以扫描回传递给printf的原始值.

我可以使用float.hderive the maximum width中的一些宏来传递到printf,但是是否已经有一个说明符可以自动打印到所需的significant digits个数字——或者至少打印到最大宽度?

推荐答案

我推荐@Jens Gustedt十六进制解决方案:使用%a.

OP希望"以最大精度打印(或至少打印到最有效的小数点)".

一个简单的示例是打印七分之一,如下所示:

#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01

但让我们更深入地挖洞...

从数学上讲,答案是"142857 142857 142857……",但是我们使用的是有限精度的浮点数. 我们假设是IEEE 754 double-precision binary. 所以OneSeventh = 1.0/7.0的结果是下面的值.还示出了前面和后面的可表示的double个浮点数.

OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh        = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after  = 0.1428571428571428 769682682968777953647077083587646484375

打印doubleexact十进制表示法用途有限.

C在<float.h>个宏中有2个宏家族可以帮助我们

FLT_DECIMAL_DIG   6,  9 (float)                           (C11)
DBL_DECIMAL_DIG  10, 17 (double)                          (C11)
LDBL_DECIMAL_DIG 10, 21 (long double)                     (C11)
DECIMAL_DIG      10, 21 (widest supported floating type)  (C99)

第二组是significant位数,字符串可以扫描成浮点,然后打印FP,仍然保留相同的字符串表示形式.图中显示了C规范的minimum值和一个sample C11编译器.我相信C99之前就有了.

FLT_DIG   6, 6 (float)
DBL_DIG  10, 15 (double)
LDBL_DIG 10, 18 (long double)

第一组宏似乎达到了OP的significant位数目标.但macro并不总是可用.

#ifdef DBL_DECIMAL_DIG
  #define OP_DBL_Digs (DBL_DECIMAL_DIG)
#else  
  #ifdef DECIMAL_DIG
    #define OP_DBL_Digs (DECIMAL_DIG)
  #else  
    #define OP_DBL_Digs (DBL_DIG + 3)
  #endif
#endif

"+3"是我先前答覆的症结所在. 它的中心是如果知道往返转换字符串-fp-string(设置#2宏可用C89),如何确定fp-string-fp的位数(设置#1宏可用后C89)?一般来说,结果是加3.

现在知道要打印的significant位数是多少,并通过<float.h>驱动.

要打印N个significant位十进制数字,可以使用各种格式.

对于"%e"precision字段是指after位数,即前导位数和小数点.

printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01

对于"%f",precision字段是小数点after的位数. 对于像OneSeventh/1000000.0这样的数字,需要OP_DBL_Digs + 6才能看到所有的significant位数字.

printf("%.*f\n", OP_DBL_Digs    , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285

注:许多是使用到"%f".它在小数点后显示6位;6是显示默认值,而不是数字的精度.

C++相关问答推荐

错误:八进制常数中的数字9无效

带双指针的2D数组

Mise()在虚拟内存中做什么?

在32位处理器上优化53—32位模计算>

如何将字符串传递给函数并返回在C中更改的相同字符串?

如何在不使用其他数组或字符串的情况下交换字符串中的两个单词?

在我的代码中,我需要在哪里编写输出函数?

struct -未知大小

如何用c语言修改shadow文件hash部分(编程)?

S和查尔有什么不同[1]?

当b是无符号字符时,int a=(b<;<;2)>;>;2;和int a=b&;0x3F;之间有什么区别?

如何将C中的两个字符串与从文件接收的字符串中的字符数进行比较

C语言中MPI发送接收字符串时出现的分段错误

GCC错误,共享内存未定义引用?

如何组合两个宏来初始化C语言中的字符串数组?

生成一个半RNG,结果用C表示(无随机/随机)

我编写这段代码是为了判断一个数字是质数、阿姆斯特朗还是完全数,但由于某种原因,当我使用大数时,它不会打印出来

为什么argc和argv即使在主函数之外也能工作?

C 程序不显示任何输出,但它接受 CS50 Lab1 的输入问题

获取 struct 中匿名 struct 的大小