为啥编译器将浮点数的位数固定为 6?

Posted

技术标签:

【中文标题】为啥编译器将浮点数的位数固定为 6?【英文标题】:Why do compilers fix the digits of floating point number to 6?为什么编译器将浮点数的位数固定为 6? 【发布时间】:2015-04-08 09:06:31 【问题描述】:

根据The C++ Programming Language - 4th第 6.2.5 节

共有三种浮点类型:float(单精度)、double(双精度)和 long double(扩展精度)

参考:http://en.wikipedia.org/wiki/Single-precision_floating-point_format

真正的有效位包括二进制点右侧的 23 个小数位和一个值为 1 的隐式前导位(二进制点左侧),除非指数以全零存储。 因此只有 23 个小数位出现在内存格式中,但总精度为 24 位(相当于 log10(224) ≈ 7.225 个十进制数字)。

→ 浮点数的最大位数是binary32 interchange format 上的7 位数。 (在计算机内存中占用 4 个字节(32 位)的计算机数字格式)

当我在不同的编译器(如 GCC、VC 编译器)上进行测试时 → 它总是输出6 作为值。

查看每个编译器的float.h → 我发现6固定的

问题:

你知道为什么这里会有不同(实际值理论值 - 7 - 和实际值 - 6 之间)吗? 听起来 "7" 更合理,因为当我使用下面的代码进行测试时,该值仍然有效,而 "8" 无效 为什么编译器不检查交换格式以决定浮点数表示的位数(而不是使用固定值)?

代码:

#include <iostream> 
#include <limits>

using namespace std;

int main( )

    cout << numeric_limits<float> :: digits10 << endl;

    float f = -9999999;

    cout.precision ( 10 );

    cout << f << endl;

【问题讨论】:

“它总是输出 6 作为值。” 这可以从您的问题的其余部分推断出来,但以后请告诉我们“它”是什么。跨度> 相关:***.com/q/6302172/560648 阅读floating-point-gui.de 【参考方案1】:

您没有阅读文档


std::numeric_limits&lt;float&gt;::digits10 是 6:

std::numeric_limits&lt;T&gt;::digits10 的值是T 类型可以表示的base-10 位数,无需更改,即任何具有这么多十进制位数的数字都可以转换为类型的值T 并返回十进制形式,不会因舍入或溢出而改变。对于基数类型,它是数字的值(浮点类型为digits-1)乘以 log10(radix)并向下舍入。

标准的 32 位 IEEE 754 浮点类型有 24 位小数部分(写入 23 位,隐含一位),这可能表明它可以表示 7 位小数(24 * std::log10(2) 为 7.22),但 相对舍入误差是不均匀的,一些具有 7 个十进制数字的浮点值在转换为 32 位浮点数并返回时无法幸存:最小的正例是 8.589973e9,在往返。 这些舍入误差在表示中不能超过一位,digits10 计算为(24-1)*std::log10(2),即6.92。四舍五入得到值 6。


std::numeric_limits&lt;float&gt;::max_digits10 是 9:

std::numeric_limits&lt;T&gt;::max_digits10 的值是唯一表示 T 类型的所有不同值所必需的 base-10 数字的数量,例如序列化/反序列化为文本所必需的。此常量对所有浮点类型都有意义。

与大多数数学运算不同,只要至少使用了max_digits109 用于float17 用于double),浮点值与文本之间的转换就是精确的:即使中间文本表示不准确,也保证产生相同的浮点值。用十进制表示法表示浮点数的精确值可能需要一百多个十进制数字。

【讨论】:

我参考了一些维基页面和cplusplus.com/reference/limits/numeric_limits【参考方案2】:

std::numeric_limits&lt;float&gt;::digits10 等同于 FLT_DIG,由 C 标准定义:

小数位数,q,这样任何具有 q 个小数位的浮点数都可以四舍五入为具有 p 基数 b 位的浮点数,然后再次返回,而无需更改为 q 个小数位,

⎧ p log10 b 如果 b 是 10 的幂

⎩ ⎣( p − 1) log10 b⎦ 否则

FLT_DIG 6

DBL_DIG 10

LDBL_DIG 10

值 6(而不是 7)的原因是由于舍入错误 - 并非所有具有 7 个十进制数字的浮点值都可以用 32 位 float 无损表示。舍入误差限制为 1 位,因此 FLT_DIG 值是基于 23 位(而不是完整的 24 位)计算的:

23 * log10(2) = 6.92

四舍五入为6

【讨论】:

报价渲染不佳。

以上是关于为啥编译器将浮点数的位数固定为 6?的主要内容,如果未能解决你的问题,请参考以下文章

为啥将浮点数除以整数返回 0.0?

为啥 as_tibble() 将浮点数舍入到最接近的整数?

如何将浮点数打印到 n 位小数,包括尾随 0?

将浮点数转换为字符串而不会丢失精度

在C语言中,如何将一个浮点数变换成整数?

Javascript将浮点数转换为指数[重复]