| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2158 人关注过本帖, 1 人收藏
标题:简单的问题,但自己不会
只看楼主 加入收藏
gukai1991
Rank: 2
等 级:论坛游民
帖 子:19
专家分:51
注 册:2011-2-19
收藏
得分:0 
回复 7楼 lisanhu1
对于这个问题以后注意,以后直接指出问题所在
2011-03-25 18:50
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:0 
说了今天晚上来答,不能食言~

首先你得知道怎么把十进制转成二进制。

手算时要分别转整数和小数。

整数是不断除二,反向取余数:
比如 13 = 8 + 4 + 1,即 2^3 + 2^2 + 2^0。所以二进制是 1101
可用竖式算得,如下:
    1 | 13 (13 除以2 商6 余1)
    0 | 6
    1 | 3
    1 | 1        // 修正修正,原先写的是 2,挺明显的一个错误。谢谢 shamoor 指出。
      | 0
算法是,不断除二,把商写在下面,余数写在左边。(这个不太好打,你就凑合着看把,反正会算就行)
然后从下往上看就是 1101

小数部分是不断乘二,取整数部分。
比如 0.8125 = 0.5 + 0.25 + 0.0625 = 1/2 + 1/4 + 1/16,所以写成二进制是 0.1101
用竖式算是:
    1 | 0.8125 (0.8125 乘以2得1.625,整数部分是1,小数部分是0.625)
    1 | 0.625
    0 | 0.25
    1 | 0.5
      | 0
算法是,不断乘二,把整数部分写在左边,小数部分写在下面。到0为止。
这个是从上往下看的。所以就是 0.1101

此时就有 13.8125 写成二进制就是 1101.1101。


先会这个,再看你那个题。

咱们先算 3.3
3 = 2+1,即是二进制 11,没得说。
0.3:
    0 | 0.3
    1 | 0.6
    0 | 0.2
    0 | 0.4
    1 | 0.8
    1 | 0.6
    ... ...
0.6 又出现了。

这就比较有意思了,虽然 0.3 在十进制里很平常,但在二进制里是无限循环小数。
所以 3.3 是 11.0100110011001....
同理可以算得 1.1 是 1.0001100110011001....

这两个都是无限小数,在计算机这种二进制的世界里显然无法精确表示。


IEEE 标准里(好像是754标准吧,是个规定浮点运算相关的标准)规定了浮点数的表示方法。
统一用类似科学计数法的方法表示:m * 2^n。
m 称为尾数(Fraction),n 称为阶数或者指数(exponent),还有一个符号位来表示正负。
并要求要调整指数,比如 1101.1101 * 2^0 要写成 1.1011101 * 2^3。此时指数就是 3,当然要用二进制的11;尾数是 1.1011101。由于这么一移,整数部分必然是用1开头的,没必要多浪费一位。所以尾数部分不储存首1。即 m 是 1011101。

当然情况没这么简单,还可能有的数是 0.001,就得写成 1 * 2^-3。这么一来,指数又得有正负,为了避免这个,指数还要用偏移码的方法表示。
标准里规定的比较详细。我这说的叫正规浮点数,还有非正规的。还有用来表示正负无穷大的(INF),表示无意义值的(NaN),无意义值又有很多种类,用于表示不同的错误,等等。我不详细介绍了。


具体来说:
32位(4字节的,相当于 float)的浮点数,有1位符号位,8位指数位,23位尾数位。
64位(8字节的,如double),有1位符号,11位指数,52位尾数。
好像标准里还有16位的,我记不得了。有兴趣的自己查。

既然尾数有限,就存不下无限小数,存不下的值就抛弃了。
至于你问为什么除出来是 2.99999 这个其实可以算,但我实在不想算了。
乘除法的机器算法用的是位移加减,你可以自己手算。查下资料,把那52位数写出来,先指数对齐,再位移最多不超过52次,做减法,就能得到。


我觉得楼主大概知道这么多,也不是那么疑惑了。这些知识在计算机组成原理里都有讲。
会不会这些,对 C 这种高级语言来说不是那么太重要了。同样的算法在不同的编译器上,不同的系统上,不同的硬件上,跑下来的值在小数点很后面的几位有点微小的偏差是很正常的事情。(虽然 GNU 的有些文档,也指出这种行为是它们软件的BUG,不过他们说了这种 BUG 改善不了)

不要太纠结。一般来说把低精度的往高数度的转,如 int 转 double 是没问题的,相反的转法一般是不可取,精度损失太大。
像这个例子,根据 2楼 提供的数据,本来 double 算下来,誤差也就是几百亿分之一,结果一转变成1了。好的编译器,应该在这种情况给中等级别以上的警告提示。

硬件方面我也只是会 intel 的 80x86 的架构。别的不是很清楚,不过这个工程标准规定的东西,肯定什么设备都一样。


[ 本帖最后由 pangding 于 2011-4-4 20:26 编辑 ]
收到的鲜花
  • 寒风中的细雨2011-03-25 22:59 送鲜花  10朵  
  • lisanhu12011-03-26 00:30 送鲜花  5朵   附言:好文章
2011-03-25 22:36
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:1 
回复 12楼 pangding
觉得这个帖子可以  置顶
单精度:32bit
双精度:64bit
扩展精度:80bit 1  16 63
   
2011-03-25 22:58
BlueGuy
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:29
帖 子:4476
专家分:4055
注 册:2009-4-18
收藏
得分:1 

会不会这些,对 C 这种高级语言来说不是那么太重要了。同样的算法在不同的编译器上,不同的系统上,不同的硬件上,跑下来的值在小数点很后面的几位有点微小的偏差是很正常的事情。(虽然 GNU 的有些文档,也指出这种行为是它们软件的BUG,不过他们说了这种 BUG 改善不了)
//
你答的实在是太精彩了,

前几天我还想买本IEEE 浮点数标准学习一下, 翻开一看觉得没什么必要, 还是买本  photoshop比较实用,
 

我就是真命天子,顺我者生,逆我者死!
2011-03-26 09:40
wskcb
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2011-3-26
收藏
得分:1 
变量定义有问题。。
2011-03-26 11:08
wskcb
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2011-3-26
收藏
得分:0 
回复 12楼 pangding
很给力啊
2011-03-26 11:13
lucky563591
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:4
帖 子:765
专家分:2103
注 册:2009-11-18
收藏
得分:1 
计算机运算又不像人那样,它把除法变成乘法,再转化为加法,最后就是2点多,舍余后等于2
2011-03-27 07:54
xyz326547445
Rank: 1
等 级:新手上路
帖 子:5
专家分:0
注 册:2011-3-28
收藏
得分:1 
我也是编程新人,看了后很受启发。
2011-03-28 13:43
白苏
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2011-3-28
收藏
得分:1 
double的运算中,3.3读出的是3.2999999999...1.1读出的是1.0999999999........
得到的double型是2.9999999999......
强转成int型便得到2喽!
2011-03-28 22:14
loverson
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2011-4-3
收藏
得分:0 
刚进入论坛就收益匪浅呐,12楼的解释真是详尽啊,相信一般的新手看了都会明白的
2011-04-03 18:39
快速回复:简单的问题,但自己不会
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017762 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved