js数值精度和大数、小数计算

JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1与1.0是相同的,是同一个数。
根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。

第1位:符号位,0表示正数,1表示负数
第2位到第12位:指数部分
第13位到第64位:小数部分(即有效数字)

符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。

IEEE 754 规定,有效数字第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字总是1.xx…xx的形式,其中xx…xx的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript 提供的有效数字最长为53个二进制位。
(-1)^符号位 * 1.xx...xx * 2^指数位
上面公式是一个数在 JavaScript 内部实际的表示形式。

精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-(253-1)到253-1,都可以精确表示。

根据标准,64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示。

如果指数部分等于或超过最大正值1024,JavaScript 会返回Infinity(关于Infinity的介绍参见下文),这称为“正向溢出”;如果等于或超过最小负值-1023(即非常接近0),JavaScript 会直接把这个数转为0,这称为“负向溢出”。

js 小数运算问题

5-3.2=1.7999999999999998
原因:
java和JavaScript中计算小数运算时,都会先将十进制的小数换算到对应的二进制,一部分小数并不能完整的换算为二进制,这里就出现了第一次的误差。待小数都换算为二进制后,再进行二进制间的运算,得到二进制结果。然后再将二进制结果换算为十进制,这里通常会出现第二次的误差。
十进制数字 8,用二进制表示为 100

可以理解为 122+0*21+02^0 = 8

那么小数部分怎么表示?
十进制数字 0.5,用二进制表示为 0.1
可以理解为 0*20+1*(2-1) = 0.5

十进制数字 0.25,用二进制表示为 0.01
可以理解为 020+0*(2-1)+1(2^-2) = 0.25

十进制数字 0.75,用二进制表示为 0.11
可以理解为 020+1*(2-1)+1(2^-2) = 0.75

好了,问题来了 怎么表示一个 介于 0.25~0.5 之间的数?
解决方法:

要避免这种情况呢,通常可以将小数同时扩大相同10的整倍数,完成计算后,在去掉之前添加的整倍数。

js大数加、减、乘(整数)运算

	//加法
	function jia(a, b) {
		//把a,b放进zong数组
		var zong = [String(a), String(b)];
		//创建fen数组
		var fen = [];
		//把a,b较大的放在前面
		zong = getMax(zong[0], zong[1]);
		//把zong数组里面的元素分成单个数字
		zong[0] = zong[0].split('');
		zong[1] = zong[1].split('');
		//创建加0变量
		var jialing;
		//判断两个参数是否相同长度
		if(!(zong[0].length == zong[1].length)) {
			//创建0
			jialing = new Array(zong[0].length-zong[1].length+1).join('0');
			//把0放进zong[1]前面
			zong[1] = jialing.split('').concat(zong[1]);
		}
		//创建补充上一位的数字
		var next = 0;
		//从个位数起对应单个计算
		for(var i=(zong[0].length-1); i>=0; i--) {
			//求和
			var he = Number(zong[0][i]) + Number(zong[1][i]) + next;
			//把求和的个位数先放进数组
			fen.unshift(he%10);
			//把求和的十位数放进补充上一位的数字,留在下一次循环使用
			next = Math.floor(he/10);
			//判断最后一次如果求和的结果为两位数则把求和的十位数加在最前面
			if(i == 0 && !(next==0)) {
				fen.unshift(next);										
			}						
		}
		//把最后的结果转化成字符串
		var result = fen.join('');
		//返回字符串
		return result;
	}
 
	//减法
	function jian(a, b) {
		var zong = [String(a), String(b)];
		var fen = [];
		zong = getMax(zong[0], zong[1]);
		if(zong.length == 3) {
			alert("金币不足");
			return false;
		}
		zong[0] = zong[0].split('');
		zong[1] = zong[1].split('');
		var jialing;
		if(!(zong[0].length == zong[1].length)) {
			jialing = new Array(zong[0].length-zong[1].length+1).join('0');
			zong[1] = jialing.split('').concat(zong[1]);
		}
		var next = 0;
		for(var i=(zong[0].length-1); i>=0; i--) {
			var cha = Number(zong[0][i]) - Number(zong[1][i]) - next;
			next = 0;
			if(cha<0) {
				cha = cha + 10;
				next = 1;
			}
			fen.unshift(cha%10);					
		}
		var result = fen.join('');
		if(result[0] == 0) {
			result = shanchuling(result);
		}
		return result;	
	}
 
	//乘法
	function cheng(a, b) {
		var zong = [String(a), String(b)];
		var fen = [];
		zong = getMax(zong[0], zong[1]);
 
		zong[0] = zong[0].split('');
		zong[1] = zong[1].split('');
		//获取b的长度,处理乘法分配率的乘法
		for(var j=(zong[1].length-1); j>=0; j--) {
			var next = 0;
			var fentemp = []; 
			var jialing = '';
			//获取a的长度处理乘法
			for(var i=(zong[0].length-1); i>=0; i--) {
				var ji = Number(zong[0][i]) * Number(zong[1][j]) + next;
				fentemp.unshift(ji%10);
				next = Math.floor(ji/10);
				if(i == 0 && !(next==0)) {
					fentemp.unshift(next);										
				}
			}
			//后面添加0
			jialing = new Array((zong[1].length-(j+1))+1).join('0');
			fentemp.push(jialing);			
			fen[j] = fentemp.join('');				
		}
		//处理乘法后的求和
		var cishu = fen.length;
		for(var k=1; k<cishu; k++) {
			var hebing = jia(fen[0], fen[1]);
			fen.splice(0,2,hebing);
		}
		
		var result = fen.join('');
		if(result[0] == 0) {
			result = shanchuling(result);
		}	
		return result;
	}
 
	//获取最大值
	function getMax(a, b) {
		var result = [a, b];
		//如果a长度小于b长度
		if(a.length<b.length)
		{
			//b放前面
			result[0] = b;
			result[1] = a;
			//返回result长度为3,为了减法的不够减而准备
			result[2] = 'not';
			//返回最终数组
			return result;
		}
		//如果a长度等于b长度
		if(a.length == b.length) {
			//循环对比a,b里面的单个元素
			for(var i=0; i<a.length; i++) {
				if(result[0][i]>result[1][i]) {
					result[0] = a;
					result[1] = b;
					return result;
				}
				if(result[0][i]<result[1][i]) {
					result[0] = b;
					result[1] = a;
					result[2] = 'not';
					return result;					
				}
				//假如全部相等,当最后一个元素,以上条件都不执行,则执行默认的返回结果
				if(i == a.length-1) {
					return result;
				}				
			}
		}
		if(a.length>b.length) {
			return result;				
		}
	}
 
	//删除字符串前面多余的0
	function shanchuling(result) {
		//首先判断是否全部都是0,是的话直接返回一个0
		if(result == 0) {
			result = 0;
			//返回最终字符串
			return result;
		}
		//把字符串分割成数组
		result = result.split('');	
		//获取数组长度
		var hebing = result.length;
		for(var j=0; j<hebing; j++) {
			//判断数组首位是否为0
			if(result[0] == 0) {
				//把数组首位删掉
				result.splice(0,1);
			}
			else {
				//删除完了就跳出循环
				break;
			}
		}
		//返回最终字符串
		return result;		
	}
	//用法
	//console.log(jia("123","123"));
	//console.log(jian("123","123"));
	//console.log(cheng("123","123"));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值