den*_*631 11 c c++ floating-point precision floating-point-conversion
问题是,我不太明白为什么double可以存储比unsigned long long更多的数字.由于它们都是8字节长,所以64位.
在无符号长long中,所有64位用于存储值,另一方面double表示1表示,11表示指数,52表示尾数.即使用于尾数的52位将用于存储没有浮点的十进制数,它仍然有63位......
但LLONG_MAX明显小于DBL_MAX ......
为什么?
Dam*_*mon 25
原因是unsigned long long
它将存储精确的整数,而double
存储尾数(具有有限的52位精度)和指数.
这允许double
存储非常大的数字(大约10 308)但不完全相同.a中有大约15个(大约16个)有效十进制数字,double
308个可能的小数的其余部分是零(实际上是未定义的,但为了更好地理解,你可以假设为"零").
一个unsigned long long
只有19位,但他们中的每一个被精确定义.
编辑:
回复下面的评论"这是如何工作",你有1位的符号,11位为指数,52位为尾数.尾数在开头有一个隐含的"1"位,没有存储,所以有效地你有53个尾数位.2 53是9.007E15,所以你有15个,几乎16个十进制数字可以使用.
指数有一个符号位,范围从-1022到+1023,用于缩放(二进制左移或右移)尾数(2 1023约为10 307,因此限制范围),所以非常小,这种格式同样可以使用非常大的数字.
但是,当然,您可以表示的所有数字只能具有适合matissa的精度.
总而言之,浮点数不是很直观,因为"简单"十进制数不一定表示为浮点数.这是因为尾数是二进制的.例如,可以(并且很容易)表示任何高达几十亿的正整数,或者数字如0.5或0.25或0.0125,具有完美的精度.
另一方面,也可以表示像10 250这样的数字,但仅约为数字.事实上,你会发现10 250和10 250 +1是相同的数字(等待,什么???).这是因为尽管您可以轻松拥有250个数字,但您没有那么多有效数字(将"重要"视为"已知"或"已定义").
此外,尽管0.3甚至不是"大"数字,但代表看起来像0.3这样简单的东西也是可能的.但是,你不能用二进制表示0.3,无论你附加什么二进制指数,你都不会找到任何导致精确为0.3的二进制数(但你可以非常接近).
一些"特殊值"保留为"无穷大"(正面和负面)以及"非数字",因此您的总理论范围略小于此.
unsigned long long
另一方面,不以任何方式解释位模式.您可以表示的所有数字都只是位模式表示的确切数字.每个数字的每个数字都是精确定义的,不会发生缩放.
pax*_*blo 13
IEEE754浮点值可以存储更大范围的数字,因为它们牺牲了精度.
通过这种方式,我的意思是64位整数类型可以表示其范围内的每个单独值,但64位双精度表示不能.
例如,尝试存储0.1
到双精灵实际上不会给你0.1
,它会给你一些像:
0.100000001490116119384765625
Run Code Online (Sandbox Code Playgroud)
(这实际上是最接近的单精度值,但同样的效果将适用于双精度).
但是,如果问题是"如何使用更少的可用位来获得更大的范围?",则只需使用其中一些位来扩展该值.
经典示例,假设您有四位十进制数来存储值.使用整数,您可以0000
通过9999
包含来表示数字.该范围内的精度是完美的,您可以表示每个积分值.
但是,让我们进入浮点并使用最后一位数作为比例,以便数字1234
实际代表数字.123 x 104
所以,现在你的范围是从0
(表示为0000
通过0009
)至999,000,000,000
(表示为9999
是).999 x 109
但你不能代表所有的数字中该范围.例如,123,456
无法表示,你可以得到的壁橱是1233
给你的数字123,000
.事实上,在整数值精度为四位数的情况下,现在只有三位数.
这基本上是IEEE754的工作方式,牺牲了范围的精度.
这是尝试提供有关浮点编码如何工作的易于理解的解释.这是一种简化,它不包括真正的IEEE 754浮点标准的任何技术方面(归一化,有符号零,无穷大,NaN,舍入等).但是,这里提出的想法是正确的.
理解浮点数如何工作受到以下事实的严重阻碍:计算机使用基数来处理,2
而人类不能轻易处理它们.我将尝试解释浮点数如何使用base工作10
.
让我们使用符号和基数10
(即我们每天使用的常用数字)0
来构造浮点数表示9
.
比方说,我们有10
方形电池和每个单元可以承装符号(+
或-
)或十进制数(0
,1
,2
,3
,4
,5
,6
,7
,8
或9
).
我们可以使用10位数来存储有符号整数.符号的一位数和值的9位数:
sign -+ +-------- 9 decimal digits -----+
v v v
+---+---+---+---+---+---+---+---+---+---+
| + | 0 | 0 | 0 | 0 | 0 | 1 | 5 | 0 | 0 |
+---+---+---+---+---+---+---+---+---+---+
Run Code Online (Sandbox Code Playgroud)
这是值如何1500
表示为整数.
我们也可以用它们来存储浮点数.例如,尾数为7位,指数为3位:
+------ sign digits --------+
v v
+---+---+---+---+---+---+---+---+---+---+
| + | 0 | 0 | 0 | 1 | 5 | 0 | + | 0 | 1 |
+---+---+---+---+---+---+---+---+---+---+
|<-------- Mantissa ------->|<-- Exp -->|
Run Code Online (Sandbox Code Playgroud)
这是1500
浮点值的可能表示之一(使用我们的10位十进制数字表示).
mantissa(M
)+150
的值是,exponent(E
)的值是+1
.上面表示的值是:
V = M * 10^E = 150 * 10^1 = 1500
Run Code Online (Sandbox Code Playgroud)
整数表示可以在-(10^9-1)
(-999,999,999
)和+(10^9-1)
(+999,999,999
)之间存储有符号值.此外,它可以表示这些限制之间的每个整数值.更重要的是,每个值都有一个表示,而且确切.
浮点表示可以存储尾数(符号值M
)之间-999,999
以及+999,999
和指数(E
)之间-99
和+99
.
它可以存储-999,999*10^99
和之间的值+999,999*10^99
.这些数字有105
数字,远远超过9
上面表示为整数的最大数字.
让我们注意,对于整数值,M
存储符号和值的前6位(或更少),并且E
是不适合的位数M
.
V = M * 10^E
Run Code Online (Sandbox Code Playgroud)
让我们尝试V = +987,654,321
使用我们的浮点编码来表示.
因为M
仅限于+999,999
它只能存储+987,654
和E
将+3
(最后3位数V
不能适应M
).
把它们放在一起:
+987,654 * 10^(+3) = +987,654,000
Run Code Online (Sandbox Code Playgroud)
这不是我们的原始值,V
但我们可以使用此表示得到最佳近似值.
我们的言论,所有的(含)之间的数字+987,654,000
,并+987,654,999
使用相同的值近似的(M=+987,654, E=+3
).此外,没有办法存储大于的数字的十进制数字+999,999
.
作为一般规则,对于大于M
(+999.999
)的最大值的数字,此方法为+999,999*10^E
和之间的所有值生成相同的表示形式+999,999*10^(E+1)-1
(整数或实数值,无关紧要).
对于较大的值(大于最大值M
),浮点表示在它可以表示的数字之间存在间隙.随着价值的E
增加,这些差距变得越来越大.
"浮点"的整个概念是存储十几个最具代表性的数字(数字的开头)和数字的大小.
我们以光速为例.它的价值是300,000 km/s
.如此大规模的,最实用的目的,你不关心它是否300,000.001 km/s
还是300,000.326 km/s
.
事实上,它甚至不是那么大,更好的近似
299,792.458 km/s
.
浮点数提取了光速的重要特征:其幅度为数十万km/s(E=5
),其值为3
(数十万km/s).
speed of light = 3*10^5 km/s
Run Code Online (Sandbox Code Playgroud)
我们的浮点表示可以近似它:299,792 km/s
(M=299,792
,E=0
).