为什么在C ++ 17中使用十六进制浮点常量?

时间:2016-04-01 04:46:40

标签: c++ floating-point constants c++17

C ++ 17添加十六进制浮点常量(floating point literal)。为什么?几个例子展示了这些好处。

2 个答案:

答案 0 :(得分:8)

浮点数存储在基数2的x86 / x64处理器中,而不是基数10:https://en.wikipedia.org/wiki/Double-precision_floating-point_format。由于许多十进制浮点数不能精确表示,例如十进制0.1可以表示为0.1000000000000003或0.0999999999999997 - 无论基数2表示是否接近十进制0.1。由于这种不精确性,例如以十进制打印然后解析浮点数可能会导致与打印前存储在存储器中的数字略有不同。

对于某些应用程序,此类错误的出现是不可接受的:它们希望解析与打印前完全相同的二进制浮点数(例如,一个应用程序导出浮点数据和另一个导入)。为此,可以以十六进制格式导出和导入双精度数。因为16是2的幂,所以二进制浮点数可以用十六进制格式精确表示。

printfscanf已使用%a格式说明符进行了扩展,该说明符允许打印和解析十六进制浮点数。虽然MSVC++ does not support %a format specifier for scanf尚未:

  

scanf无法使用a和A说明符(请参阅printf类型字段字符)。

要以十六进制格式打印全精度double,应指定点后13个十六进制数字的打印,对应13 * 4 = 52位:

double x = 0.1;
printf("%.13a", x);

查看有关hexadecimal floating point with code and examples的更多详细信息(请注意,至少对于%a中的printf的MSVC ++ 2013简单规范,在点之后打印6个十六进制数字,而不是13 - 最后说明该文章)。

特别是对于常量,如问题所述,十六进制常量可以方便地在精确的硬编码浮点输入上测试应用程序。例如。您的错误可以重现0.1000000000000003,但不适用于0.0999999999999997,因此您需要十六进制硬编码值来指定十进制0.1的感兴趣表示。

答案 1 :(得分:1)

使用十六进制浮点数超过小数的两个主要原因是准确性和速度。

用于精确转换十进制常量和浮点数的基础二进制格式的算法是surprisingly complicated,甚至现在conversion errors still occasionally arise

十六进制和二进制之间的转换是一个更简单的努力,并保证是准确的。一个示例用例是当您使用特定浮点数而不是任何一方时(例如,对于exp等特殊函数的实现),这一点非常重要。这种简单性也使转换速度更快(它不需要任何中间" bignum"算术):在某些情况下,我发现对于hex float vs的读/写操作加速3倍小数。