printf 宽度说明符以保持浮点值的精度 [英] Printf width specifier to maintain precision of floating-point value

查看:29
本文介绍了printf 宽度说明符以保持浮点值的精度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一个 printf 宽度说明符可以应用于浮点说明符,该说明符会自动将输出格式化为必要数量的有效数字,以便在扫描string back in,获取的是原来的浮点值?

Is there a printf width specifier which can be applied to a floating point specifier that would automatically format the output to the necessary number of significant digits such that when scanning the string back in, the original floating point value is acquired?

例如,假设我将 float 打印到 2 个小数位的精度:

For example, suppose I print a float to a precision of 2 decimal places:

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

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

When I scan the output 0.94, I have no standards-compliant guarantee that I'll get the original 0.9375 floating-point value back (in this example, I probably won't).

我想要一种方法告诉 printf 自动将浮点值打印到必要数量的有效数字,以确保它可以扫描回原始传递给 printf 的值.

I would like a way tell printf to automatically print the floating-point value to the necessary number of significant digits to ensure that it can be scanned back to the original value passed to printf.

我可以使用 float.h 中的一些宏来导出最大宽度传递给 printf,但是是否已经有一个说明符可以自动打印到必要数量的有效数字——或者至少到最大宽度?

I could use some of the macros in float.h to derive the maximum width to pass to printf, but is there already a specifier to automatically print to the necessary number of significant digits -- or at least to the maximum width?

推荐答案

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

I recommend @Jens Gustedt hexadecimal solution: use %a.

OP 想要以最大精度(或至少到最重要的小数点)打印".

OP wants "print with maximum precision (or at least to the most significant decimal)".

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

A simple example would be to print one seventh as in:

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

<小时>

但让我们深入挖掘......


But let's dig deeper ...

数学上,答案是0.142857 142857 142857 ...",但我们使用的是有限精度浮点数.让我们假设 IEEE 754 双精度二进制.所以 OneSeventh = 1.0/7.0 产生下面的值.还显示了前后可表示的 double 浮点数.

Mathematically, the answer is "0.142857 142857 142857 ...", but we are using finite precision floating point numbers. Let's assume IEEE 754 double-precision binary. So the OneSeventh = 1.0/7.0 results in the value below. Also shown are the preceding and following representable double floating point numbers.

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

打印double精确十进制表示的用途有限.

Printing the exact decimal representation of a double has limited uses.

C 在 中有 2 个宏系列来帮助我们.
第一组是以十进制形式打印在字符串中的有效位数,因此在扫描字符串时,我们得到原始浮点数.显示了 C 规范的最小值值和一个示例 C11 编译器.

C has 2 families of macros in <float.h> to help us.
The first set is the number of significant digits to print in a string in decimal so when scanning the string back, we get the original floating point. There are shown with the C spec's minimum value and a sample C11 compiler.

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)

第二组是一个字符串可能被扫描成浮点数然后打印 FP 的重要位数,仍然保留相同的字符串表示.显示了 C 规范的最小值值和示例 C11 编译器.我相信在 C99 之前可用.

The second set is the number of significant digits a string may be scanned into a floating point and then the FP printed, still retaining the same string presentation. There are shown with the C spec's minimum value and a sample C11 compiler. I believe available pre-C99.

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

第一组宏似乎满足了 OP 的有效 数字目标.但是那个并不总是可用.

The first set of macros seems to meet OP's goal of significant digits. But that macro is not always available.

#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.

The "+ 3" was the crux of my previous answer. Its centered on if knowing the round-trip conversion string-FP-string (set #2 macros available C89), how would one determine the digits for FP-string-FP (set #1 macros available post C89)? In general, add 3 was the result.

现在要打印多少有效数字是已知的,并通过驱动.

Now how many significant digits to print is known and driven via <float.h>.

要打印 N 重要 十进制数字,可以使用多种格式.

To print N significant decimal digits one may use various formats.

对于"%e"precision 字段是 前导数字和小数点之后的位数.所以 -1 是有序的.注意:这个-1不在初始int Digs = DECIMAL_DIG;

With "%e", the precision field is the number of digits after the lead digit and decimal point. So - 1 is in order. Note: This -1 is not in the initial int Digs = DECIMAL_DIG;

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

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

With "%f", the precision field is the number of digits after the decimal point. For a number like OneSeventh/1000000.0, one would need OP_DBL_Digs + 6 to see all the significant digits.

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

注意:许多用于"%f".即显示小数点后6位数字;6 是显示默认值,不是数字的精度.

Note: Many are use to "%f". That displays 6 digits after the decimal point; 6 is the display default, not the precision of the number.

这篇关于printf 宽度说明符以保持浮点值的精度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆