动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > Java教程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ Java教程 ]的信息

本月文章推荐
.特性信息.
.Struts应用程序的流程控制简介.
.Java Servlet API说明文档(2.1a.
.自动转向的javabean源码.
.一个Socket服务器样板程.
.Jrockit在redhat7.3下的安装使用.
.j2se_api_中文.
.java中的易混问题收集.
.Java的秘密:将应用程序的设定存.
.Thinking in Java (the 2nd edit.
.Sprite类中的defineReferencePix.
.javazip_src_0.8alpha源代码发布.
.JBuilder5+Weblogic 6.0安装配置.
.企业级应用中的Applet和Servlet的.
.跨越边界: Java 模型以外的类型策.
.集成EJB和CORBA/CORBA客户端访问.
.Java 线 程 的 讨 论 与 应 用 (.
.MySQL实施JDBC 2.0/3.0 API的新特.
.Java开发工具及其获得方法.
.装饰模式(Decorator Pattern)(.

谨慎使用单精度/双精度这两数值类型

发表日期:2008-1-5 |



  前言
  
  在近日几个帖子里面,和QQ群的讨论里面,我发现很多网友都碰到的问题都是因为不恰当地使用了单精度/双精度数值。因此想专门就这个话题谈一下。
  
  单精度和双精度数值类型最早出现在C语言中(比较通用的语言里面),在C语言中单精度类型称为浮点类型(Float),顾名思义是通过浮动小数点来实现数据的存储。这两个数据类型最早是为了科学计算而产生的,他能够给科学计算提供足够高的精度来存储对于精度要求比较高的数值。但是与此同时,他也完全符合科学计算中对于数值的观念:
  
  当我们比较两个棍子的长度的时候,一种方法是并排放着比较一下,一种方法是分别量出长度。但是事实上世界上并不存在两根完全一样长的棍子,我们测量的长度精度受到人类目测能力和测量工具精度的限制。从这个意义上来说,判定两根棍子是否一样长丝毫没有意义,因为结果一定是False,但是我们可以比较他们两个哪个更长或者更短。这个例子很好地概括了单精度/双精度数值类型的设计初衷和存在意义。
  
  基于上述熟悉,单精度/双精度数值类型从一开始设计的时候,就不是一个准确的数值类型,他只保证在他这个数值类型的精度之内是准确的,精度之外则不保证,比方说,一个数值5.1,很可能存储在单精度/双精度数值中的实际值是5.100000000001或者5.09999999999999。导致这个现象的原因我们可以通过两种方式来解释:
  
  简单的解释方法:
  
  你可以尝试在任何一个控件的属性面板中,设定他的宽度为:3.2CM,当你输入完毕后,你会发现值自动变成了3.199cm,无论你怎么改,你都无法输入3.200CM,因为实际上在电脑中存储的并不是CM为单位的数值,而是“缇”为单位的数值,而“缇”和CM之间的比值,是个很难被除尽的数,因此你输入完毕后,电脑自动转换成了最接近的“缇”值,然后再转换成厘米显示到属性面板上,这一乘一除,两次四舍五入,误差就出来了。单精度/双精度也是类似的原理,其实在二进制存储的时候,单精度/双精度都采用了类似相近分数的方法,而这样的存储是不可能做到准确的。
  
  深入的解释方法:
  
  让我们来看看我们存储到数字介质中的单精度/双精度值到底是怎么样的,我们使用如下代码对单精度类型进行一个解剖:
  
  Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
  
  Public Sub floatTest()
  Dim dblVar As Single
  
  dblVar = 5.731 / 8
  dblOutput dblVar
  
  dblVar = dblVar * 2
  dblOutput dblVar
  
  dblVar = dblVar * 2
  dblOutput dblVar
  
  dblVar = dblVar * 2
  dblOutput dblVar
  
  dblVar = dblVar * 2
  dblOutput dblVar
  
  dblVar = dblVar * 2
  dblOutput dblVar
  
  End Sub
  
  Public Sub dblOutput(ByVal dblVar As Single)
  Dim bytVar(3) As Byte
  Dim i As Integer, j As Integer
  Dim strVar As String
  
  CopyMemory ByVal VarPtr(bytVar(0)), ByVal VarPtr(dblVar), 4
  strVar = dblVar & ": "
  For i = 3 To 0 Step -1
  For j = 7 To 0 Step -1
  strVar = strVar & (bytVar(i) And 2 ^ j) / 2 ^ j
  Next j
  strVar = strVar & " "
  Next i
  Debug.Print strVar
  
  End Sub
  运行后我们得到输出结果(输出格式为高位左,低位右):
  
  .716375: 00111111 00110111 01100100 01011010
  1.43275: 00111111 10110111 01100100 01011010
  2.8655: 01000000 00110111 01100100 01011010
  5.731: 01000000 10110111 01100100 01011010
  11.462: 01000001 00110111 01100100 01011010
  22.924: 01000001 10110111 01100100 01011010
  
  这里,我们把单精度类型转化成了二进制数据输出,这里我们看到,虽然这六个数字完全不同,但是他们的二进制存储惊人地相似,我们看到红色标记部分,每次都是加1,事实上,单精度数据类型使用从高位开始第1位作为正负标记位(绿色),第2位到第9位,是一个跨字节的有符号字节类型数据,这个数值决定了小数点移动的方向和位数(红色),第10位到32位保存一个整数(蓝色)在存储过程中,电脑首先把输入的值不断移位(乘除2)直到这个数的整数部分占用了全部24位的整数位,然后把移动的位数写入浮点部分(红色),而移位后的结果写入整数部分(蓝色和绿色),小数部分则舍弃。求值的时候则是反向过程,先根据正负位和整数位求值,然后根据红色部分的整数来进行移位(乘除2的次方),最终才是我们得到的单精度数值。双精度数值也是同样原理,只是位数更多而已。
  
  通过解剖单精度数值的二进制存储格式,我们可以清楚看到,实际上单精度/双精度的存储,都要通过乘法和除法,其中必有舍入,假如恰好你的数值在除法中被舍入了,那么你赋的初值就很可能与你最终存储的值不完全相同,其中的微小差异,并不与单精度/双精度的设计目标相违反。
  
  当我们在数据库中或者VBA代码中使用一个单精度/双精度数值的时候,也许你从界面上看不到区别,但是在实际的存储中,这个差别却真真切切地就在那里,当你对其进行相等比较的时候,系统只是简单地作二进制的比较,界面上无法体现的微小差异,在二进制比较面前却无处遁形,于是,你的等于比较返回了一个意料之外的False。
  
  结束语
  
  通过本文,我们介绍了单精度/双精度数据类型的实质以及其特点(优点和缺点),通过比较和解剖我们了解到单精度/双精度实际上存储的是一个近似值,浮点的特性决定了他可以存储非常小的数,也可以存储极大的数,他的数据精度并不是一个绝对值,而是存储值的百分比,假如你存储10的100次方,误差就可能是10的80次方,假如你存储10的-100次方,误差就可能是10的-120次方。因此单精度/双精度数据类型不能进行相等的比较(或数据库关联)。
  
  假如你需要进行等值比较或关联,那么有以下几种方案:
  
  1、使用专为准确度而设计的货币类型。
  
  2、使用整数类型存储,代码中移位。
  
  3、某些特定情况下可以用文字存储。
上一篇:如何实现用jacob来调用word的宏 人气:901
下一篇:datagrid数据列/模板列/按钮事件+操作类 人气:717
浏览全部Java的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-10-10 企业网站智能管理系统(TZIMS) v6
2008-10-10 拓文asp.net网站内容管理系统 v6
2008-10-10 动网论坛PHP版 v2.0++ Build 081
2008-10-10 免费时代CMS v5.0
2008-10-10 wodig第四季中文DIGG社区 v4.1 b
2008-10-10 老Y文章管理系统 v2.2 bulid 081
2008-10-10 魔法盒动感相册 ASP+SQL版 v2.0
2008-10-10 Asoft签到管理系统 v3.0 Pack1
2008-10-10 哥特人音乐网潮流留言本 v1.1
2008-9-29 酷狗音乐(原KuGoo)2008 v5.310 正
2008-9-29 QQTab 1.1
2008-9-29 网络传送带 Net Transport 2.64a
2008-9-29 谷歌金山词霸v1.8
2008-9-29 TweakVI 1.0 Build 1090
2008-9-29 ACDSee Pro 2.5 Build 333 汉化绿
2008-9-29 Winamp v5.541(2189) 周明波简体
2008-9-27 CCleaner 2.12.651
2008-9-27 Mozilla Thunderbird 2.0.0.17 英
  发表评论
姓 名: 验证码:
内 容:
站长工具:网站收录查询 | Google PR查询 | ALEXA排名查询 | CSS在线编辑器 | 广告代码 | js/vbs加密 | md5加密 | 进制转换 | UTF-8 转换工具 | Html转换js | Html转换asp | Html转换php | Html转换perl
实用工具:汉字翻译拼音 | 拼音字典 | 符号对照表 | 个税计算 | 实时汇率查询换算 | 经典小工具 | 汉字简繁转换 | 普通单位换算 | 公制单位换算 | 生辰老黄历 | 国内电话区号 | 国家代码与域名缩写 | 文字加密解密 | 健康查询 | 万年历 | 汉字横竖排版 | 手机号码查询 | 计算器 | ip搜索
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号