JS-----震惊0.1+0.2不等于0.3

惊闻 0.1 + 0.2 !== 0.3

前几天在学习JS语言,在做一个计算器时发现了一个神奇的东西,0.1+0.2不等于0.3,也就是(0.1 + 0.2 == 0.3)的值为false,先来看一下在JS中它给出的和是多少

<script type="text/javascript">
			var flag=(0.1+0.2==0.3);
			alert(flag);	//弹框为true	
			alert(0.1+0.2);
		</script>

js浮点精度.JPG验证.JPG
当然这不是一个特例,在js中只要小数参加了四则运算它的精度都会发生丢失

<script type="text/javascript" language="javascript">     
    alert(1/3);//弹出: 0.3333333333333333  
    alert(0.09999999 + 0.00000001);//弹出: 0.09999999999999999   
    alert(-0.09999999 - 0.00000001);//弹出: -0.09999999999999999  
    alert(0.012345 * 0.000001);//弹出: 1.2344999999999999e-8  
    alert(0.000001 / 0.0001);//弹出: 0.009999999999999998  
</script>

为什么?

  • 个人理解
    由于数字编码方式的局限性,因此在其进行十进制与二进制准换时,会存在位数上的变化,所以计算机是不能准确的表达出一个小数的,只能是无限的去逼近。
    如果要比较两个浮点型的数据是否相等,那我们也可以采用无限逼近的方式来做
if(fabs(0.3-(0.1+0.2)) < 1E-10)
  • 专业一点的
    JavaScript的number类型按照ECMA的JavaScript标准,它的Number类型就是IEEE 754的双精度数值,相当于java的double类型。IEEE 754标准《二进制浮点数算法》(www.ieee.org)就是一个对实数进行计算机编码的标准。因此精度问题不止JS这门语言独有。

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

    绝对完美的数值编码方案是不存在的,为了处理方便,这个标准引入了大量的折衷和妥协,建立在这种表达方式上的算法(例如除法运算)也一样。由于数值表达方式存在“缺陷”,运算结果不可避免地堆聚起越来越多的误差。
    参考资料

如何解决

1. 利用四舍五入来限制精度
	var v=(0.1+0.3).toFixed(3)//保留小数点后3位
			alert(v)//弹0.300

这种方法虽然可以解决问题,但也存在一定的局限性,比如说我想要计算5位小数,那它不就歇菜了,没关系我们再说一种刚刚学到的操作】

2. 小数转正数进行计算

既然精度问题是由于小数转换时的位数变化引起的,那么我们就直接将小数化为整数进行运算,算完之后再将它转回去,不就可以了

  • 加法
//加法
		Number.prototype.add = function(arg) {
			var r1, r2, m;
			try {
				r1 = this.toString().split(".")[1].length
			} catch (e) {
				r1 = 0
			}
			try {
				r2 = arg.toString().split(".")[1].length
			} catch (e) {
				r2 = 0
			}
			m = Math.pow(10, Math.max(r1, r2))
			return (this * m + arg * m) / m
		}
  • 减法
		//减法
		Number.prototype.sub = function(arg) {
			return this.add(-arg);
		}
  • 乘法
		//乘法
		Number.prototype.mul = function(arg) {
			var m = 0,
				s1 = this.toString(),
				s2 = arg.toString();
			try {
				m += s1.split(".")[1].length
			} catch (e) {}
			try {
				m += s2.split(".")[1].length
			} catch (e) {}
			return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
		}
  • 除法
		//除法
		Number.prototype.div = function(arg) {
			var t1 = 0,
				t2 = 0,
				r1, r2;
			try {
				t1 = this.toString().split(".")[1].length
			} catch (e) {}
			try {
				t2 = arg.toString().split(".")[1].length
			} catch (e) {}
			with(Math) {
				r1 = Number(this.toString().replace(".", ""))
				r2 = Number(arg.toString().replace(".", ""))
				return (r1 / r2) * pow(10, t2 - t1);
			}
		}
// 			5674.784   t1 3    r1*1000  5674784   
// 			0.323342   t2 6    r2*1000000  0323342	

这个算法还是比较好理解的,整理下来方便以后使用
这篇博客从数据结构上给出了分析,可以参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值