CenturyMagus的专栏

www.err123.cn ,收集各类编程错误的解决方案,欢迎大家访问

用户操作
[即时聊天] [发私信] [加为好友]
magusID:CenturyMagus
62903次访问,排名1684好友2人,关注者3
CenturyMagus的文章
原创 42 篇
翻译 1 篇
转载 40 篇
评论 23 篇
CenturyMagus的公告

ah011一起在友播听歌吧!
最近评论
zhengyuanting:通过URL传中文,如果不是post的话,是会乱码的
qq386232894:好文章!!!!
fz04003:谢谢啊,我终于搞懂这个东西了。
虽然我用的是JQuery,但是终于搞懂Struts这块是怎么回事了,谢谢!
小脚:终于全部搞懂了!!!谢谢老大~
小小鸟:好文章.比其他好多地方都讲的清楚透彻.赞一个.
文章分类
收藏
    相册
    编程网站
    Apache
    IBM DeveloperWorks
    onjava
    W3C
    编程错误解决方案收集
    计算机词汇在线词典
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 java学习之数值型别(int,float,double等)收藏

    新一篇: Linux下的压缩文件剖析 | 旧一篇: 血型漫画,挺好玩的

    1. 代码

    2.Java中数字类型的转换法则

    test1中看似除数中的所有的因子都被约掉了,只剩下了1000。但实际的输出却是5,而不是我们期望的1000。究其原因,是因为MICROS_PER_DAYint类型进行的计算,而计算的结果是86400000000,已经超出了int类型的最大值,即溢出了(int32位,2^31-1=2147483647),24*60*60*1000*1000最后的结果是500654080(见程序中的print1的输出)

     

    在产生了错误的计算结果后,该结果被付给了long型的MICROS_PER_DAYlong型为64位,故保持了这个错误的结果,最终导致了最终结果的错误。

     

    解决该问题的方法是,通过使用long常量来代替int常量作为每一个乘积的第一个因子,这样就可以强制表达式中所有的后续计算都使用long运算来完成,这样就不会丢失精度,即:

    long MICROS_PER_DAY = 24L*60*60*1000*1000;

    图中的六个实箭头表示了无信息损失的转换,而三个虚箭头表示的转换则可能丢失精度。

     

    3.浮点类型float, double的数据不适合在不容许舍入误差的金融计算领域。

    例如上面的test2,我们预期的得到的结果是0.1,但实际的输出却是0.8999999999999999

     

    这种误差产生的原因是因为浮点数实际上是用二进制系统表示的。而分数1/10在二进制系统中没有精确的表示,其道理就如同在十进制系统中无法精确表示1/3一样。看完下面的第4点就可以明白其中的原因了。

     

    如果需要进行不产生舍入误差的精确数字计算,需要使用BigDecimal类。

     

    4.既然说到了浮点型是使用二进制表示的,那么就再来复习以下这方面的内容。

     1)简单介绍下IEEE754标准

     Java中的float,double以及其对应的包装类FloatDouble,都依据IEEE754标准。

     一个实数VIEEE 754标准中可以用V(1)s×M×2E 的形式表示,说明如下:

          (1)符号s (sign)决定实数是正数(s0)还是负数(s1),对数值0的符号位特殊处理。

          (2)有效数字M是二进制小数,M的取值范围在1≤M20≤M1

           说明:尾数M原码表示。

                         根据原码的规格化方法,最高数字位(整数部分)总是1,该标准将这个1缺省

                         存储,使得尾数表示范围比实际存储的一位。M存储的只是小数部分。

                         (看到后面的例子就会明白啦)

          (3)指数E2的幂,它的作用是对浮点数加权。

           说明:由于E是用移码表示,32位的float类型需要加上偏移量12764位的double

                         类型要加上偏移量1023

     

    下图即为float32位)和double64位)的存储格式:

     

    2)十进制小数与二进制小数的相互转换

    1:二进制转十进制

    2十进制数转换成二进制数,是把整数部分和小数部分分别转换,整数部分用2除,取余数,小数部分用2乘,取整数位。

    如:(13.125)10转换成二进制数

    1)整数部分:13/2 6  1

                 6/2  3  0

                 3/2  1  1

                 1/2  0  1

    故整数部分为 1101

     

    2)小数部分:

    因此,

     

    3) 下面再举几个规范化表示的例子(float类型为例)

    a)       十进制小数1.25

    二进制表示为1.01

    规范化二进制表示即 *1.01*

    符号位:0

    指数部分:0+127=127

                         01111111

    尾数部分:01000000000000000000000

    注:尾数部分只存储了小数部分的(0.01),整数部分的1是默认存储的。这正好 

           验证了4-1)-(2)要说明的问题。

    最终结果为 0 01111111 01000000000000000000000

     

    b)      十进制小数0.75

    二进制表示为0.11

    规范化表示即 *1.1*

    符号位:0

    指数部分:-1+127=126

                         01111110

    尾数部分:10000000000000000000000

     

    最终结果: 0 01111110 10000000000000000000000

     

     

    c)      十进制-2.5

    二进制表示为 -10.1

                    规范化后为 *1.01*

                    符号位:1

                    指数部分:1+127=128

                                         10000000

                    尾数部分:01000000000000000000000

             最终结果:1 10000000 01000000000000000000000

     

       注:浮点数一般都存在舍入误差,很多数字无法精确表示(例如0.1),其结果只能是接近, 

                但不等于。一般情况下,分母不是 的情况下,一般都无法精确表示(虽然这种表

                述可能不太严谨)。

     

    5.补充知识

    IEEE754的四种舍入方向

    向最接近的可表示的值;当有两个最接近的可表示的值时首选偶数值;向负无穷大(向 下);向正无穷大(向上)以及向0(截断)。

    说明:舍入模式也是比较容易引起误解的地方之一。我们最熟悉的是四舍五入模式,但是,IEEE 754标准根本不支持,它的默认模式是最近舍入(Round to Nearest),它与四舍五入只有一点不同,对.5的舍入上,采用取偶数的方式。举例比较如下:

    2

    最近舍入模式:Round(0.5) = 0; Round(1.5) = 2; Round(2.5) = 2;

    四舍五入模式:Round(0.5) = 1; Round(1.5) = 2; Round(2.5) = 3;

    主要理由:由于字长有限,浮点数能够精确表示的数是有限的,因而也是离散的。在两个可以精确表示的相邻浮点数之间,必定存在无穷多实数是IEEE浮点数所无法精确表示的。如何用浮点数表示这些数,IEEE 754的方法是用距离该实数最近的浮点数来近似表示。但是,对于.5,它到01的距离是一样近,偏向谁都不合适,四舍五入模式取1,虽然银行在计算利息时,愿意多给0.5分钱,但是,它并不合理。例如:如果在求和计算中使用四舍五入,一直算下去,误差有可能越来越大。机会均等才公平,也就是向上和向下各占一半才合理,在大量计算中,从统计角度来看,高一位分别是偶数和奇数的概率正好是50% : 50%。至于为什么取偶数而不是奇数,大师Knuth有一个例子说明偶数更好,于是一锤定音。

    原码、反码、补码、移码

    对于正数,原码和反码,补码都是一样的,都是正数本身。 对于负数,原码是符号位为1,数值部分取X绝对值的二进制。 反码是符号位为1,其它位是原码取反。 补码是符号位为1,其它位是原码取反,未位加1 也就是说,负数的补码是其反码未位加1 移码就是将符号位取反的补码。

     

    在计算机中,实际上只有加法运算,减法运算也要转换为加法运算, 乘法转换为加法运算,除法转换为减法运算。

     

    在计算机中,对任意一个带有符号的二进制,都是按其补码的形式进行运算和存储的。 之所以是以补码方式进行处理,而不按原码和反码方式进行处理,是因为在对带有符号位的 原码和反码进行运算时,计算机处理起来有问题。(具体原因见理解原码,反码与补码) 而按补码方式,一方面使符号位能与有效值部分一起参加运算,从而简化运算规则. 另一方面使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计

     

    发表于 @ 2008年07月06日 11:49:00|评论(loading...)|编辑|收藏

    新一篇: Linux下的压缩文件剖析 | 旧一篇: 血型漫画,挺好玩的

    评论:没有评论。

    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © CenturyMagus