关于double在内存中表现的疑惑?该如何处理
关于double在内存中表现的疑惑?
很简单的代码,我在return 0;这行打了断点。
监视中查看d value为5.0010000000000003,为什么?我赋予的值是5.001啊,虽然以前也看到过,但没有太留言,求官方版解释,呵呵。
我监视&d value为0x0012ff78 这是地址,没什么说的
然后在调试窗口--内存 中查看0x0012ff78
0x0012ff78 1B 2F DD 24 06 01 14 40 与5.0010000000000003是如何对应的?
即 如果我知道内存地址0x0012ff78处存储这一个double类型的变量,我怎么才能算出它的值呢?
求指教
谢谢
------解决方案--------------------
对于有些数,double或float是不能精确表示的,至于具体如何计算,百度一下就清楚了
------解决方案--------------------
推荐看《深入理解计算机系统》这本书。
------解决方案--------------------
c/c++中浮点数的存储方式遵循ieee标准的,参考:
float和double变量的内存布局
------解决方案--------------------
百度一下:“浮点表示法”
------解决方案--------------------
小数位:100 0000 0000 0000 0000 0000,-->1.10000000000000000000000为1.5
意思就是说读出来的100 0000 0000 0000 0000 0000是小数位,在前面隐式的加上“1.”就变成1.10000000000000000000000。它的值就等于 1 * 2 ^ 0 + 1 * 2 ^ (-1) = 1.5
把文章看全就知道了
------解决方案--------------------
#6楼的博客和#9楼的解释都忽视一个问题,有必要长篇大论补充一下 :)
VC内存值
1b 2f dd 24 06 01 14 40
是从低到高的
习惯于左边是高位,所以倒过来写
40 14 01 06 24 dd 2f 1b
对应的二进制
0100 0000 0001 0100 0000 0001 0000 0110 0011 0100 1101 1101 0010 1111 0001 1011
按IEEE浮点标准
符号部分: 0
指数部分: 100 0000 0001
小数部分: 0100 0000 0001 0000 0110 0011 0100 1101 1101 0010 1111 0001 1011
浮点值=(-1)^符号×(1+小数)×2^(指数-1023)
指数等于0x401,即十进制的1025
指数-1023=2
小数含1的次数为:
-2 -12 -18 -19 -23 -24 -26 -29 -30 -32 -33 -34 -36 -39 -41 -42 -43 -44 -48 -49 -51 -52
各减去2,得:
0 -10 -16 -17 -21 -22 -24 -27 -28 -30 -31 -32 -34 -37 -39 -40 -41 -42 -46 -47 -49 -50
把计算式稍做调整,按下式计算(与#6楼和#9楼的解释一致)
4+2^0+2^(-10)+2^(-16)+...
结果将大致是
5.0010002384185794
这与
5.0010000000000003
显然不同
这个级别的数,是可以精确到小数点后16位的,所以不应该有这么大误差
那么为什么呢?
因为如上只是原理介绍,但浮点解析时的过程并不是这样算的,而是如下
重新来过
40 14 01 06 24 dd 2f 1b
符号部分: 0
指数部分: 0x40 1,即0x401,即十进制的1025
小数部分: 0x4 01 06 24 dd 2f 1b,即0x4010624dd2f1b,即十进制的1127025806749467
2^(1025-1023)×0x4010624dd2f1b×2^(-52)
=2^(-50)×0x4010624dd2f1b
也就是说,小数部分并不按定点小数来解析,而是按定点整数来解析,然后再相乘(或者说相除),结果为
1.0010000000000003
------解决方案--------------------
用10进制小数不能精确表示某些三进制小数0.1(3)=0.33333333333……(10)
同理,用二进制小数也不能精确表示某些10进制小数。
------解决方案--------------------
悲剧的计算机组成原理
------解决方案--------------------
------解决方案--------------------
请看,查看验证float存储格式
float类型存储格式弄明白,也明白了double类型
- C/C++ code
int main() { double d =5.001; return 0; }
很简单的代码,我在return 0;这行打了断点。
监视中查看d value为5.0010000000000003,为什么?我赋予的值是5.001啊,虽然以前也看到过,但没有太留言,求官方版解释,呵呵。
我监视&d value为0x0012ff78 这是地址,没什么说的
然后在调试窗口--内存 中查看0x0012ff78
0x0012ff78 1B 2F DD 24 06 01 14 40 与5.0010000000000003是如何对应的?
即 如果我知道内存地址0x0012ff78处存储这一个double类型的变量,我怎么才能算出它的值呢?
求指教
谢谢
------解决方案--------------------
对于有些数,double或float是不能精确表示的,至于具体如何计算,百度一下就清楚了
------解决方案--------------------
推荐看《深入理解计算机系统》这本书。
------解决方案--------------------
c/c++中浮点数的存储方式遵循ieee标准的,参考:
float和double变量的内存布局
------解决方案--------------------
百度一下:“浮点表示法”
------解决方案--------------------
小数位:100 0000 0000 0000 0000 0000,-->1.10000000000000000000000为1.5
意思就是说读出来的100 0000 0000 0000 0000 0000是小数位,在前面隐式的加上“1.”就变成1.10000000000000000000000。它的值就等于 1 * 2 ^ 0 + 1 * 2 ^ (-1) = 1.5
把文章看全就知道了
------解决方案--------------------
#6楼的博客和#9楼的解释都忽视一个问题,有必要长篇大论补充一下 :)
VC内存值
1b 2f dd 24 06 01 14 40
是从低到高的
习惯于左边是高位,所以倒过来写
40 14 01 06 24 dd 2f 1b
对应的二进制
0100 0000 0001 0100 0000 0001 0000 0110 0011 0100 1101 1101 0010 1111 0001 1011
按IEEE浮点标准
符号部分: 0
指数部分: 100 0000 0001
小数部分: 0100 0000 0001 0000 0110 0011 0100 1101 1101 0010 1111 0001 1011
浮点值=(-1)^符号×(1+小数)×2^(指数-1023)
指数等于0x401,即十进制的1025
指数-1023=2
小数含1的次数为:
-2 -12 -18 -19 -23 -24 -26 -29 -30 -32 -33 -34 -36 -39 -41 -42 -43 -44 -48 -49 -51 -52
各减去2,得:
0 -10 -16 -17 -21 -22 -24 -27 -28 -30 -31 -32 -34 -37 -39 -40 -41 -42 -46 -47 -49 -50
把计算式稍做调整,按下式计算(与#6楼和#9楼的解释一致)
4+2^0+2^(-10)+2^(-16)+...
结果将大致是
5.0010002384185794
这与
5.0010000000000003
显然不同
这个级别的数,是可以精确到小数点后16位的,所以不应该有这么大误差
那么为什么呢?
因为如上只是原理介绍,但浮点解析时的过程并不是这样算的,而是如下
重新来过
40 14 01 06 24 dd 2f 1b
符号部分: 0
指数部分: 0x40 1,即0x401,即十进制的1025
小数部分: 0x4 01 06 24 dd 2f 1b,即0x4010624dd2f1b,即十进制的1127025806749467
2^(1025-1023)×0x4010624dd2f1b×2^(-52)
=2^(-50)×0x4010624dd2f1b
也就是说,小数部分并不按定点小数来解析,而是按定点整数来解析,然后再相乘(或者说相除),结果为
1.0010000000000003
------解决方案--------------------
用10进制小数不能精确表示某些三进制小数0.1(3)=0.33333333333……(10)
同理,用二进制小数也不能精确表示某些10进制小数。
------解决方案--------------------
悲剧的计算机组成原理
------解决方案--------------------
------解决方案--------------------
请看,查看验证float存储格式
float类型存储格式弄明白,也明白了double类型