Binary 浮点精度是可变的还是不变的?
对于浮点数(即Binary 浮点精度是可变的还是不变的?,binary,floating-point,decimal,floating-point-precision,significant-digits,Binary,Floating Point,Decimal,Floating Point Precision,Significant Digits,对于浮点数(即float、double、或long double)是否有一个且只有一个精度值,或者是否有一个可以变化的精度值,我的答案总是褒贬不一 一个被称为的主题似乎暗示浮点精度是绝对的 但是另一个话题叫, 通常,双精度的小数位数为15到16 另一个说, 浮点型变量的精度通常为约7位有效数字 double类型变量的精度通常为约16位有效数字 如果我使用的是敏感代码,当我的值不精确时,这些代码很容易被破坏,我不喜欢参考上面的近似值。所以,让我们澄清一下。浮点精度是可变的还是不变的,原因是什么?精
float
、double
、或long double
)是否有一个且只有一个精度值,或者是否有一个可以变化的精度值,我的答案总是褒贬不一
一个被称为的主题似乎暗示浮点精度是绝对的
但是另一个话题叫,
通常,双精度的小数位数为15到16
另一个说,
浮点型变量的精度通常为约7位有效数字
double类型变量的精度通常为约16位有效数字
如果我使用的是敏感代码,当我的值不精确时,这些代码很容易被破坏,我不喜欢参考上面的近似值。所以,让我们澄清一下。浮点精度是可变的还是不变的,原因是什么?精度是固定的,对于双精度,精确到53位二进制数字(或者52位,如果我们排除隐式前导1)。这大约是15位十进制数字
OP让我详细解释一下为什么正好有53个二进制数字意味着“大约”15个十进制数字
为了直观地理解这一点,让我们考虑一个不太精确的浮点格式:代替一个52位尾数的双精度数字,我们只需要使用一个4位尾数。 因此,每个数字看起来像:(-1)s×2yyy×1.xxxx(其中
s
是符号位,yyy
是指数,1.xxxx
是标准化尾数)。对于当前的讨论,我们将只关注尾数,而不是符号或指数
下面是一个表格,列出了所有xxxx
值的1.xxxx
外观(所有舍入都是一半到偶数,就像默认的浮点舍入模式一样):
xxxx | 1.xxxx |值| 2dd | 3dd
--------+----------+----------+-------+--------
0000 | 1.0000 | 1.0 | 1.0 | 1.00
0001 | 1.0001 | 1.0625 | 1.1 | 1.06
0010 | 1.0010 | 1.125 | 1.1 | 1.12
0011 | 1.0011 | 1.1875 | 1.2 | 1.19
0100 | 1.0100 | 1.25 | 1.2 | 1.25
0101 | 1.0101 | 1.3125 | 1.3 | 1.31
0110 | 1.0110 | 1.375 | 1.4 | 1.38
0111 | 1.0111 | 1.4375 | 1.4 | 1.44
1000 | 1.1000 | 1.5 | 1.5 | 1.50
1001 | 1.1001 | 1.5625 | 1.6 | 1.56
1010 | 1.1010 | 1.625 | 1.6 | 1.62
1011 | 1.1011 | 1.6875 | 1.7 | 1.69
1100 | 1.1100 | 1.75 | 1.8 | 1.75
1101 | 1.1101 | 1.8125 | 1.8 | 1.81
1110 | 1.1110 | 1.875 | 1.9 | 1.88
1111 | 1.1111 | 1.9375 | 1.9 | 1.94
你说它提供了多少个十进制数字?你可以说是2,因为两个十进制数字范围内的每个值都被覆盖,尽管不是唯一的;也可以说3,它覆盖了所有唯一的值,但不覆盖三位小数范围内的所有值
为了便于论证,我们将说它有两个十进制数字:十进制精度将是那些十进制数字的所有值都可以表示的位数
好吧,那么,如果我们将所有数字减半(因此我们使用的是
yyy
=-1),会发生什么呢
xxxx | 1.xxxx |值| 1dd | 2dd
--------+----------+-----------+-------+--------
0000 | 1.0000 | 0.5 | 0.5 | 0.50
0001 | 1.0001 | 0.53125 | 0.5 | 0.53
0010 | 1.0010 | 0.5625 | 0.6 | 0.56
0011 | 1.0011 | 0.59375 | 0.6 | 0.59
0100 | 1.0100 | 0.625 | 0.6 | 0.62
0101 | 1.0101 | 0.65625 | 0.7 | 0.66
0110 | 1.0110 | 0.6875 | 0.7 | 0.69
0111 | 1.0111 | 0.71875 | 0.7 | 0.72
1000 | 1.1000 | 0.75 | 0.8 | 0.75
1001 | 1.1001 | 0.78125 | 0.8 | 0.78
1010 | 1.1010 | 0.8125 | 0.8 | 0.81
1011 | 1.1011 | 0.84375 | 0.8 | 0.84
1100 | 1.1100 | 0.875 | 0.9 | 0.88
1101 | 1.1101 | 0.90625 | 0.9 | 0.91
1110 | 1.1110 | 0.9375 | 0.9 | 0.94
1111 | 1.1111 | 0.96875 | 1. | 0.97
按照与以前相同的标准,我们现在处理的是1位小数。因此,您可以看到,根据指数的不同,您可以有更多或更少的十进制数字,因为二进制和十进制浮点数之间没有清晰的映射
同样的论点也适用于双精度浮点数(尾数为52位),只有在这种情况下,根据指数,你才能得到15或16位十进制数字。答案很简单,但很复杂。这些数字以二进制形式存储。根据它是浮点还是双精度,计算机使用不同数量的二进制来存储数字。您得到的精度取决于二进制文件。如果你不知道二进制数是如何工作的,最好查一查。但简单地说,有些数字比其他数字需要更多的1和0
因此,精度是固定的,但实际精度取决于使用的数字。浮点变量的类型定义了值的范围以及可以表示的小数位数(!)。由于十进制分数和二进制分数之间没有整数关系,因此十进制分数实际上是一个近似值 第二:另一个问题是执行精确的算术运算。想想
1.0/3.0
或PI。这样的值不能用有限的数字来表示——既不是十进制的,也不是二进制的。因此,这些值必须四舍五入以适应给定的空间。小数位数越多,精度越高
现在考虑应用多个这样的操作,例如PI/3.0。这需要四舍五入两次:PI a
/*
1 234567890123456789 */
1.000000000000000000...
1.000000000000000222...
/*
1 234567890123456789 */
8.521812787393891
8.521812787393891142073699...
8.521812787393892
void Kaboom( float a, float b, float c ) // same is true for other floating point types.
{
float sum1 = a+b+c;
float sum2 = a+b;
sum2 += c; // let's assume that the compiler did not keep sum2 in a register and the value was write to memory then load again.
if (sum1 !=sum2)
throw "kaboom"; // this can happen.
}