Wan*_*ool 38 floating-point binary decimal significant-digits floating-point-precision
我不断得到浮点数(即float,, double或long double)是否只有一个精度值,或者具有可以变化的精度值的混合答案.
一个名为float vs. double precision的主题似乎暗示浮点精度是绝对的.
然而,另一个叫做float和double之间差异的话题说,
通常,double具有15到16个十进制数字的精度
另一位消息人士称
float类型的变量通常具有大约 7位有效数字的精度
double类型的变量通常具有大约 16位有效数字的精度
如果我正在使用敏感代码,当我的值不准确时,我不喜欢引用上面的近似值.所以让我们记录下来吧.浮点精度是可变的还是不变的,为什么?
Chr*_*ung 29
精度是固定的,对于双精度,精确到53个二进制数字(如果我们排除隐式前导1,则精度为52).这大约是15位小数.
OP要求我详细说明为什么正好有53个二进制数字意味着"约"15个十进制数字.
为了直观地理解这一点,让我们考虑一种不太精确的浮点格式:而不是像双精度数字那样的52位尾数,我们只是使用4位尾数.
因此,每个数字看起来像:( - 1)s ×2 yyy ×1.xxxx(其中s是符号位,yyy是指数,1.xxxx是标准化的尾数).对于即时讨论,我们只关注尾数而不是符号或指数.
这是一个1.xxxx所有xxxx值的表格(所有舍入都是一半到偶数,就像默认的浮点舍入模式一样):
xxxx | 1.xxxx | value | 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
Run Code Online (Sandbox Code Playgroud)
你说提供了多少个十进制数字?你可以说2,因为两位小数位范围内的每个值都被覆盖,尽管不是唯一的; 或者你可以说3,它涵盖所有唯一值,但不提供三位数范围内所有值的覆盖率.
为了论证,我们会说它有2个十进制数字:小数精度将是可以表示这些十进制数字的所有值的位数.
好的,那么,如果我们将所有数字减半(所以我们使用yyy= -1)会发生什么?
xxxx | 1.xxxx | value | 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
Run Code Online (Sandbox Code Playgroud)
按照与以前相同的标准,我们现在处理1个十进制数字.因此,您可以看到,根据指数,您可以有更多或更少的十进制数字,因为二进制和十进制浮点数不会相互干净地映射.
相同的参数适用于双精度浮点数(使用52位尾数),只有在这种情况下,您将获得15或16个十进制数字,具体取决于指数.
gna*_*729 24
所有现代计算机都使用二进制浮点运算.这意味着我们有一个二进制尾数,单精度通常为24位,双精度为53位,扩展精度为64位.(在x86处理器上可以使用扩展精度,但在ARM或其他类型的处理器上则不行.)
24,53,和64位尾数意味着对于一个浮点数2之间ķ和2 K + 1的下一个较大数为2 ķ23,2 K-52和2 K-63分别.这是决议.每个浮点运算的舍入误差最多为其一半.
那么它如何转化为十进制数? 这取决于.
取k = 0和1≤X <2,分辨率为2 -23,2 -52,和2 -63,其为约1.19×10 -7,2.2×10 -16,和1.08×10 -19分别.这有点小于7,16和19位小数.然后取k = 3和
8≤x<16.两个浮点数之间的差值现在大8倍.对于8≤x<10,你只得到6,小于15,并且分别只有18位小数.但是对于10≤x<16,你会得到更多一位小数!
如果x只小于2 k + 1且只有10 n以上,例如1000≤x<1024,则得到最高的十进制数.如果x只是一个,则得到最小的十进制数位高于2 ķ和比特小于10 ñ,例如1/1024个 ≤X < 1/1000.相同的二进制精度可以产生十进制精度,最多可达1.3位数或log 10(2×10).
当然,您可以阅读文章" 每个计算机科学家应该了解的关于浮点运算的内容".
使用其硬件协处理器(最初为8087)的80x86代码提供三个级别的精度:32位,64位和80位.那些非常严格遵循1985年的IEEE-754标准.最近的标准规定了128位格式.浮点格式具有24,53,65和113个尾数位,对应于精度的7.22,15.95,19.57和34.02十进制数字.
公式为mantissa_bits/log_2 10,其中10的对数基数为3.321928095.
虽然任何特定实现的精度都不会改变,但是当浮点值转换为十进制时可能会出现这种情况.请注意,该值0.1没有精确的二进制表示.它是一个重复位模式(0.0001100110011001100110011001100 ...),就像我们习惯于十进制一样,0.3333333333333大约是1/3.
许多语言通常不支持80位格式.某些C编译器可能会提供long double使用80位浮点数或128位浮点数的编译器.唉,它也可能使用64位浮点数,具体取决于实现方式.
NPU具有80位寄存器,并使用完整的80位结果执行所有操作.在NPU堆栈内计算的代码可从此额外精度中受益.遗憾的是,代码生成不良或代码编写不当可能会将中间计算存储在32位或64位变量中,从而截断或舍入中间计算.
浮点精度是可变的还是不变的,为什么?
通常,给定相同2次幂范围内的任何数字,浮点精度是不变的 - 固定值.绝对精度随每个2阶功率而变化.在整个FP范围内,精度大致相对于幅度.在的小数精度方面与此相对二进制精度招致摇摆变化之间DBL_DIG和DBL_DECIMAL_DIG十进制数字-典型地15至17.
什么是精度?使用FP,讨论相对精度是最有意义的.
浮点数的形式为:
签名*有效*pow(基数,指数)
它们具有对数分布.在100.0和3000.0(范围为30x)之间有大约不同的浮点数,因为它们介于2.0和60.0之间.无论底层存储表示如何,都是如此.
1.23456789e100具有与...相同的相对精度1.23456789e-100.
大多数计算机实现double为binary64.此格式具有53位二进制精度.
n1.0和2.0之间的数字具有相同的绝对精度(1(2.0-1.0)/ pow(2,52)).
64.0和128.0之间的数字也n具有相同的绝对精度1((128.0-) 64.0)/ POW(2,52).
即使在2的幂之间的数组,也具有相同的绝对精度.
在FP数的整个正常范围内,这近似于均匀的相对精度.
当这些数字表示为十进制时,精度摆动:数字1.0到2.0的绝对精度比数字2.0到4.0多1位.比4.0到8.0还多2位等
C提供DBL_DIG,DBL_DECIMAL_DIG以及他们float和他们的long double对应物. DBL_DIG表示最小相对小数精度. DBL_DECIMAL_DIG可以认为是最大相对小数精度.
通常,这意味着给定double的精度为15到17位十进制数.
考虑1.0及其下一个可表示double的数字,直到第17个有效十进制数字才会改变数字.接下来的每一个double是pow(2,-52)或约2.2204e-16相隔.
/*
1 234567890123456789 */
1.000000000000000000...
1.000000000000000222...
Run Code Online (Sandbox Code Playgroud)
现在考虑"8.521812787393891"使用16个有效十进制数字,将其下一个可表示的数字视为十进制数字.即使它们在第16位数字不同,转换为这两个字符串double也是相同的 8.521812787393891142073699....说这double有16位数的精度被夸大了.
/*
1 234567890123456789 */
8.521812787393891
8.521812787393891142073699...
8.521812787393892
Run Code Online (Sandbox Code Playgroud)
不,它是可变的.起点是非常弱的IEEE-754标准,它只能确定浮动指针数的格式,因为它们存储在内存中.单精度可以计算7位精度,双精度可以计算15位数.
但该标准的一个主要缺陷是它没有具体说明如何进行计算.而且有问题,尤其是英特尔8087浮点处理器给程序员带来了许多不眠之夜.在该芯片A显著设计缺陷是,它存储浮点值与多个比存储器格式比特.设计选择背后的理论是,这允许中间计算更精确并且导致更少的舍入误差.
听起来是个好主意,然而在实践中并没有好转.编译器编写器将尝试生成代码,以尽可能长地保留存储在FPU中的中间值.对代码速度很重要,将值存储回内存是很昂贵的.麻烦的是,他经常必须存储值,FPU中的寄存器数量是有限的,代码可能跨越函数边界.此时值被截断并失去很多精度.对源代码的微小更改现在可以产生截然不同的值.此外,程序的非优化构建产生与优化程序不同的结果.以完全不可识别的方式,您必须查看机器代码以了解结果不同的原因.
英特尔重新设计了处理器以解决此问题,SSE指令集使用与内存格式相同的位数进行计算.然而,慢慢地接受,重新设计编译器的代码生成器和优化器是一项重大投资.三大C++编译器都已切换.但是,例如.NET Framework中的x86抖动仍会生成FPU代码,它始终会生成.
然后存在系统误差,失去精度是转换和计算的必然副作用.转换首先,人类在基数10中工作,但处理器使用基数2.我们使用的漂亮的圆数,如0.1,无法在处理器上转换为漂亮的整数.0.1作为10的幂之和是完美的,但是没有2的幂的有限和产生相同的值.转换它产生无限数量的1和0,就像你不能完美地写下10/3那样.所以它需要被截断以适应处理器并产生一个偏离+/- 0.5位的值十进制值.
并且计算产生错误.乘法或除法将结果中的位数加倍,将其四舍五入以使其适合存储的值会产生+/- 0.5位错误.减法是最危险的操作,可能导致丢失大量有效数字.如果您计算1.234567f - 1.234566f,那么结果只剩下1位有效数字.这是一个垃圾结果.总结具有几乎相同值的数字之间的差异在数值算法中是非常常见的.
获得过多的系统错误最终是数学模型中的一个缺陷.举个例子,你永远不想使用高斯消除,它对精度非常不友好.并且总是考虑另一种方法,LU分解是一种很好的方法.然而,数学家参与构建模型并考虑结果的预期精度并不常见.像Numerical Recipes这样的通用书也没有足够重视精确度,尽管它通过提出更好的模型间接地引导你远离坏模型.最后,程序员经常遇到问题.嗯,这很容易,任何人都可以做到这一点,我将是一个很好的工作:)
浮点变量的类型定义了值的范围以及可以表示多少小数位(!).由于十进制和二进制分数之间没有整数关系,小数部分实际上是近似值.
第二:另一个问题是执行精确算术运算.想想1.0/3.0或PI.这些值不能用有限数量的数字表示 - 既不是十进制也不是二进制.因此,必须对值进行舍入以适应给定的空间.可用的小数位数越多,精度越高.
现在考虑应用多个此类操作,例如PI/3.0.这需要进行两次舍入:PI本身并不准确,结果也不是.如果表示变得更糟,这将松散两倍.
因此,回到float和double:float根据标准(C11,附件F,也用于其余部分)有较少的可用比特,因此roundig将不那么精确double.想想一个带有2个小数位的十进制数(m.ff,称之为浮点数)和一个带四个的数字(m.ffff,称之为double).如果double用于所有计算,则可以使用更多操作,直到结果只有2个正确的小数位数,而不是已经以float开头,即使浮点结果就足够了.
请注意,在某些(嵌入式)CPU(如ARM Cortex-M4F)上,硬件FPU仅支持folat(单精度),因此双算术成本会更高.其他MCU根本没有硬件浮点计算器,因此必须模拟我的软件(非常昂贵).在大多数GPU上,浮动也比双倍便宜得多,有时甚至超过10倍.
其他答案解释说,存储具有二进制的精确数字计数.
有一点需要了解,CPU可以在内部以不同的精度运行操作,如80位.这意味着像这样的代码可以触发:
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.
}
Run Code Online (Sandbox Code Playgroud)
更复杂的计算更有可能.
| 归档时间: |
|
| 查看次数: |
2373 次 |
| 最近记录: |