为啥编译器将浮点数的位数固定为 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<float>::digits10
是 6:
std::numeric_limits<T>::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<float>::max_digits10
是 9:
std::numeric_limits<T>::max_digits10
的值是唯一表示T
类型的所有不同值所必需的 base-10
数字的数量,例如序列化/反序列化为文本所必需的。此常量对所有浮点类型都有意义。与大多数数学运算不同,只要至少使用了
max_digits10
(9
用于float
,17
用于double
),浮点值与文本之间的转换就是精确的:即使中间文本表示不准确,也保证产生相同的浮点值。用十进制表示法表示浮点数的精确值可能需要一百多个十进制数字。
【讨论】:
我参考了一些维基页面和cplusplus.com/reference/limits/numeric_limits【参考方案2】:std::numeric_limits<float>::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?的主要内容,如果未能解决你的问题,请参考以下文章