今日更新
技术新闻
精彩专题
IBM软件技术专区
微软开发专区
技术文档中心
编程语言
网络通信
网络安全
LINUX/UNIX
软件工程与管理
数据库开发
WEB开发
企业应用与开发
移动开发
资源中心
原创专栏
开放系统世界
人才与培训
技术天地论坛
厂商列表
社区推荐

· 女性身体内部人体受孕..
· 十部顶级的变态与情色..
· 感情放纵让我毁了两个..
· 当我撞见姐姐和男友在..
· 卖淫少女惨遭泄愤民工..
· 偷拍街上的走光mm绝对..
· 百度打击google的广告
· 港娱乐圈与黑社会揭秘
赛迪网>>技术应用>>JavaScript
关键字: JavaScript
来  源: 赛迪网
JS数值处理之一二三四五
作者:俞伟明 发文时间:2004.06.15
如果你是一个Web开发者,应该也写过这种接受用户输入的JavaScript代码:

<input type="text" name="age" 
onchange="return (this.value>0)">


表面上看,这行代码不存在任何问题,但实际运行一段时间后,却发现它偶尔莫名其妙地罢工。

这行代码的问题是,用户不一定输入标准的年龄整数,他可能输入“23.5”,也可能输入“二十三”。改正的办法是加入一些转换过程,例如:

<input type="text" name="age" onchange="return parseFloat( this.value)">


JavaScript是一种脚本语言,它的设计目标之一就是尽可能地简化使用,所以它处理字符串和数值的方式极其灵活,许多操作都是隐含执行、不需要开发者干预。那么,它到底灵活到哪种程度?高度灵活和高度自动化的底下是否隐藏着陷阱?是否可以定义拥有3.5个元素的数组?1加上1000000是否一定等于1000001,而不是等于1.000E6?如何保证这个数值正确显示?

我们知道以前的许多浏览器存在数值处理方面的BUG,现在是否可以高枕无忧,或者仍然必须小心翼翼?本文为你介绍脚本引擎的数值处理限制,主要针对目前流行的浏览器,包括5.x以上的IE、4.7x以上的Netscape、1.x的Mozilla。读完本文,你将知道在浏览器中执行哪些数值操作是安全的,哪些操作是不安全的。

一种解释:科学就是描述现实世界

从表面上看,数值是一个很容易理解的概念。最常用的数值类型是整数和实数,想必你一定已经熟悉它们了。简单的例子如2和23.45;但也有复杂的例子,如互联网最大梅森素数搜索的结果已超过4百万位数字。我们知道PI(圆周率)是一个无限不循环小数,如何写出比3.141592654精度更高的PI值?一言蔽之,你根本办不到。

无论是用纸张记录数值,还是用计算机记录数值,都必须用某种编码方案来表达数值。必须理解的是,用编码表达的数值不是数值本身,而只是数值的一种人类或计算机可理解的描述。任何编码方案都有其局限,要么是表达范围(精度)方面的限制,要么是其他复杂性方面的制约。例如,“2”究竟是一个整数还是实数?或者两者都是?

从数学课上,我们知道循环的数值可以用一个句点表示,例如我们不必写1.9999……(后面加上无数个9),只要写1.9再在9上面加一个点。另外我们知道,“1点9的循环”实际上等于2,因为1+(0.90.09+0.009+…)收敛的极限就是2。也就是说,同一个数值“2”有两种表达方法。如果算上2.0000,那就有三种表达方法。所以说,并非每一个数值都只有唯一的表达方式,即使在纸上写也一样!这样一来,处理数值就很不方便、甚至难以令人接受了!

二套标准:化繁为简的折衷方案

科学理论固然美妙,不过现实生活中不可能(也没有必要)严格坚持科学理论的精密。怎么办呢?订立工程标准。例如,IEEE 754标准《二进制浮点数算法》(www.ieee.org)就是一个对实数进行计算机编码的标准。

JavaScript的数值处理就建立在这类标准之上。按照ECMA的JavaScript标准,它的Number类型就是IEEE 754的双精度数值。绝对完美的数值编码方案是不存在的,为了处理方便,这个标准引入了大量的折衷和妥协,建立在这种表达方式上的算法(例如除法运算)也一样。由于数值表达方式存在“缺陷”,运算结果不可避免地堆聚起越来越多的误差——大多数情况下,这类误差不至于引起问题,但这并不意味着你可以完全忽视,请看下面两个例子:

⑴ IEEE 754除法错误曾经使Intel的Pentium付出昂贵的代价,后来Intel不得不为发布出去的芯片BUG公开道歉,累计损失约5亿美元。

⑵ 日常的利息计算不可避免地涉及浮点运算,没有人会愿意因为计算问题而多付利息或减少收入,因此数值标准必须足够精确。

按IEEE 754格式保存的浮点数精度相当于带有15、16或17位小数位数的十进制小数,由于存在二进制和十进制的转换问题,具体的位数会发生变化。要获得最高的转换精度,必须指定17位的小数——此时可以相信前15位的精度。

你可以做个试验,在JavaScript中输出下面这些数值(注意不能作为字符串输出):0.1000000000000000000000000001(28位小数)、0.100000000000000000000000001(27位小数)、0.1000000000000000000000000456(28位小数)、0.09999999999999999999999(23位小数),显示出来的结果都是数值0.1。又如,如果输出1/3的有理数表达式,结果是0.3333333333333333。

三种格式:JavaScript的Number

实际使用中JavaScript数值还有第二种标准,它是许多计算机语言都用到的常见格式,即32位的整数,相当于C语言中的int类型。它由4个8 bit的字节构成,可以保存较小的整数。可能你已经在无意之中用过这种格式,但JavaScript不允许显式声明int,它是一种隐含的类型。

因此,JavaScript数值有三种保存方式:字符串形式的数值内容,IEEE双精度浮点数,或者是整数。
为什么JavaScript要提供一种类似int的隐含数值类型?原因有三:第一,便于执行位操作,如or(|)和移位(>>)等;二,用于数组处理;三,出于精确方面的考虑。

考虑一下数组的情况。ECMA的JavaScript标准允许每个数组有4294967295个数组元素——32 bit能保存的最大值减1,剩下的一个用来保存长度数据。当我们指定数组的索引时,JavaScript解释器判断该变量是否为一个32 bit的整数。例如,假设有一个数组var,一个变量item,如果item=2,则arr[item] = 5相当于arr[2] = 5;但是,如果索引的值看起来象是一个浮点数(或者不象数值),如item=2.0,则第三个语句相当于:arr["2.0"] = 5;。

这种表达方式很容易引起误解,似乎JavaScript支持负数和小数形式的索引值,如arr[-6]和arr[2.35]。实际上,这类特殊的索引值会被自动转换成字符串。

再举一个例子。假设索引变量slot1的初值等于1.1,arr[slot1]=10,现在我们让also11 = Math.pow(Math.pow(1.1,1/20),20),从理论上看,slot1应该仍是1.1,其实不然,浮点运算的误差将使slot1变成1.100019,如果我们再访问arr[alot1],这时的arr[slot1]就不再是原来的arr[alot1]了。

可以看到,一涉及浮点数,事情就要复杂多了。不过你也不必太担心,JavaScript会优先考虑整数。也就是说,当JavaScript遇到一个数值时,它会首先尝试按照整数来处理该数值,如行得通,则把数值保存为31 bit的整数;如果该数值不能视为整数,或超出31 bit的范围,则把数值保存为64位的IEEE 754浮点数。

在浏览器环境中,数值数据可能来自多种数据源,包括XML、XHTML、DOM以及CSS标准等都具备向JavaScript提供数据的能力。不管数据来自何处,这些数值要么被视为String,要么被视为Number,如果是后则,内部保存格式可能是整数。

四个数值:必须密切注意的临界点

聪明的读者一定想到了这样一个问题:什么时候规规矩矩的整数会突然变成捉摸不定的双精度浮点数?答案是:当它们的值变得非常庞大时,或者进入1和0之间时。所以说,1和0是首先必须注意的二个数值。

接下来,最大的Unicode值是1114111(7位数字,相当于\x41777777),而最大的RGB颜色值是16777215(8位数字,相当于#FFFFFF)。最大的32 bit带符号整数是2147483647(10位数字),-2147483648最小,所以JavaScript内部会以整数的形式保存所有Unicode值和RGB颜色。2147483647是第三个必须注意的数值,任何大于该值的数据将保存为双精度格式。

9007199254740992(16位数字)是最大的浮点数,输出时类似整数,所有Date对象(按毫秒计算)都小于该值,因此总是模拟整数的格式输出。它是第四个必须注意的数值。

最后,最大的双精度数值是1.7976931348623157e+308,超出这个范围就要算作无穷大了。

五条原则:远离误差和烦恼

■ 大多数Web页面不需要小数
避免使用小数,尽量设法使用整数。确保数组的索引都是整数。按分(而不是元)计算金额。百分比放大100倍计算以避免出现小数。尽可能不用除法(/)和模(%)运算,因为大多数情况下它们直接导致出现浮点数。如果必须使用除法,立即用Math.round方法回归整数运算。

■ 如果必须使用浮点数,则尽可能引入冗余小数位——即在程序要求的运算精度之外,再增加小数位
如果程序需要5位数字的小数精度,则在运算中至少保留6位的小数,8位更好。冗余位越多,累计误差的影响越小。

■ 避免在同一个表达式中使用相差太大或太小的数值
对两个非常接近的数值执行减法或比较操作很容易出错。将很小的数值和很大数值相加无异于浪费时间,小的数值很可能被当作0。不过,很小的数值乘以很大的数值一般不会出现问题,例如2 * 12345678会得到正确的结果24691356。但是,0.1 - 0.09的结果是0.010000000000000009。

■ 用isFinite()和isNaN()检查运算结果
通过表单提交任何数值运算结果之前,一定要先检查数据的合法性。

■ 慎用数值运算
程序涉及的数值运算越少,引入误差的可能就越小。视浮点数为贵客,不可任意驱使。

(责任编辑:代君利)




赛迪网推出“IT博客”,花不到一分钟就完成注册
评论】 【推荐】 【 】 【打印】 【关闭

·Linux专区· ·黑客攻防·
· Linux下添加硬盘、分区、格式化任务详解
· FreeBSD服务器的安装与优化之优化篇
· 初学者入门:FreeBSD服务器的安装与优化
· 金企鹅杯两岸四地开源软件大赛圆满结束
· 如何提高Linux系统安全性的十大招数
· 构筑Linux防火墙之为个人用户设置防火墙
· 谁更安全?黑客眼中的防火墙与路由器
· 识破骗局 练就识别QQ活动真伪火眼金睛
· 应用安全大有可为:目的、挑战、总结
· 道高一尺魔高一丈:安全防御的动感魅力
· 警惕网络“内”院起火 积极谋求安内之路
· HHCTRL漏洞被黑客利用 疯狂传播木马
·中国信息化· ·成功案例·
· ERP普及化是饮鸩止渴 精细化才是应用之道
· 赛门铁克第八期《互联网安全威胁报告》解析
· 抢食“数字工商” 国产中间件杀出血路
· 从IBM等操作系统的发展看软件创新的启示
· 服务成就蓝色快车 品牌是怎样炼成的?
· 三大技术应用大会合为一体甲骨文上演三重奏
· 南阳教育城域网 拆掉学校间的“围墙”
· 金算盘助申意美步入信息化快车道
· 不为人知的索尼信息化 谁是幕后英雄?
· InforBus/Q在穗高速路联网收费系统中的应用
· J2EE构建最新金融理念和运作模式的网上银行
· 食品安全令人担心 信息化能否保驾护航
*姓  名: 更多资料 了解方案 认识厂商
*单位名称:
*联系电话:
*电子邮件:
    
◆ 相关文章   ◆ 站内热点推荐
· 用JavaScript编写程序实现文本的滚动一例
· JavaScript两个在线特效
· 用JavaScript实现淡入淡出效果
· 利用JavaScript创建功能强大的GUI
· 产生渐进色效果的网页
· 网管员论坛
· 开发者之家
· WLAN无限未来
· 我是如何掉进C#的……
· 中国“人件”非正式调查

   
合作网站: IBM dW中国网站 LinuxAID 软件工程专家网 中国系统分析员 UMLChina MATRIX Mobile2008 JavaResearch 华储网 UML软件工程组织 中国JAVA手机网 JAVA中文站 金山在线 海量科技