解决JS中小数计算精度问题

目录

一、计算精度问题的解决方案(解决加法、减法、乘法精度丢失问题)

1.1、解决原理

1.2、代码示例

二、为什么会出现计算精度的问题?(知其所以然)

2.1、二进制的存储原理

三、写在最后


一、计算精度问题的解决方案(解决加法、减法、乘法、除法精度丢失问题)

1.1、解决原理

JS在计算小数时会出现精度丢失的问题,但在处理整数时却不会,我们利用这一点来解决小数计算精度丢失的问题,我们先将数字转换为字符串,然后求出可以将小数变为整数的倍数,再对长度不一致的字符串进行补0,最后再除去相应的倍数得到没有损失精度的结果。

注:小数计算精度丢失的问题不仅存在于加减法,在乘除中同样存在,所以先将小数放大再除以相应倍数的方法是行不通的!

1.2、代码示例

function calc(num1, num2, calcStr)
{
	var str1, // 转换为字符串的数字
    str2,
    ws1 = 0,// ws1,ws2 用来存储传入的num的小数点后的数字的位数
    ws2 = 0,// 赋默认值,解决当整数和小数运算时倍数计算错误导致的结果误差 
    bigger,// bigger和smaller用于加,减,除法找出小的那个数字,给后面补0,解决位数不对从而造成的计算错误的问题;乘法需要将结果除两个数字的倍数之和
    smaller,// 例如:加减除法中1.001 + 2.03 ,如果不给2.03进行补0,最后会变成1001+203,数字错位导致结果错误;乘法中1.12*1.1会放大为112*11,所以结果需要除以1000才会是正确的结果,112*11/1000=1.232
    zeroCount, // 需要补充0的个数
    isExistDot1, // 传入的数字是否存在小数点
    isExistDot2,
    sum,
    beishu = 1;
	// 将数字转换为字符串
	str1 = num1.toString();
	str2 = num2.toString();
	// 是否存在小数点(判断需要计算的数字是不是包含小数)
	isExistDot1 = str1.indexOf('.') != -1 ? true : false;
	isExistDot2 = str2.indexOf('.') != -1 ? true : false;
	// 取小数点后面的位数
	if (isExistDot1)
	{
		ws1 = str1.split('.')[1].length;
	}
	
	if (isExistDot2)
	{
		ws2 = str2.split('.')[1].length;
	}
    // 如ws1 和 ws2 无默认值,如果num1 或 num2 不是小数的话则 ws1 或 ws2 的值将为 undefined 
    // bigger 和 smaller 的值会和预期不符
	bigger = ws1 > ws2 ? ws1 : ws2;
	smaller = ws1 < ws2 ? ws1 : ws2;
	
	switch (calcStr)
	{
		// 加减法找出小的那个数字,给后面补0,解决位数不对从而造成的计算错误的问题
		// 例如:1.001 + 2.03 ,如果不给2.03进行补0,最后会变成1001+203,数字错位导致结果错误
		case "+":
		case "-":
		case "/":
			zeroCount = bigger - smaller;
			for(var i = 0; i < zeroCount; i++)
			{
				if (ws1 == smaller)
				{
					str1 += "0";
				}
				else
				{
					str2 += "0";
				}
			}
			break;
		case "*":
			// 乘法需要将结果除两个数字的倍数之和
			bigger = bigger + smaller;
			break;
		default:
			return "暂不支持的计算类型,现已支持的有加法、减法、乘法、除法";
			break;
	}
	
	// 去除数字中的小数点
	str1 = str1.replace('.', '');
	str2 = str2.replace('.', '');
	
	// 计算倍数,例如:1.001小数点后有三位,则需要乘 1000 变成 1001,变成整数后精度丢失问题则不会存在
	for (var i = 0; i < bigger; i++)
	{
		beishu *= 10; // 等价于beishu = beishu * 10;
	}
	num1 = parseInt(str1);
	num2 = parseInt(str2);
	// 进行最终计算并除相应倍数
	switch (calcStr)
	{
		case "+":
			sum = (num1 + num2) / beishu;
			break;
		case "-":
			sum = (num1 - num2) / beishu;
			break;
		case "*":
			sum = (num1 * num2) / beishu;
			break;
		case "/":
			sum = num1 / num2;
			/* 除数与被除数同时放大一定倍数,不影响结果,
			所以对数字进行放大对应倍数并进行补0操作后不用另对倍数做处理 */
			break;
		default:
			return "暂不支持的计算类型,现已支持的有加法、减法、乘法、除法";
	}
	
	return sum;
}

二、为什么会出现计算精度的问题?(知其所以然)

2.1、二进制的存储原理

在JS中不区分整数和小数,因为JS中天生浮点数(双精度),在计算机存储中,双精度的实际存储位数是52位,由于二进制中只有 0 和 1,但52位有时并不能准确的表达小数点后面的数字,在十进制中有四舍五入,在二进制中存在0舍1入,所以当52位无法准确的表达出一个小数时,就会产生补位动作,数值偏差就在这时产生了,这是造成计算精度问题的原因。

三、写在最后

本人水平有限,在文中可能有词不达意或错误之处,发出本文是想和大家探讨一下JS中小数计算的精度问题,如果本文对你产生了帮助,我会很开心☺。如果有不理解或其他建议欢迎私信交流讨论,感谢阅读!

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
在Vue解决JavaScript计算精度问题,可以使用第三方库math.js。通过引入math.js库,我们可以避免在浮点数计算出现的精度问题。 在Vue使用math.js可以按照以下步骤进行: 1. 首先,安装math.js库。可以使用npm或者yarn进行安装,例如:`npm install mathjs`。 2. 在Vue组件引入math.js库,可以使用import语句进行引入,例如:`import math from 'mathjs'`。 3. 在需要进行计算的地方,使用math.js提供的相应方法进行计算。例如,对于减法,可以使用`math.subtract()`方法,对于加法,可以使用`math.add()`方法,对于除法,可以使用`math.divide()`方法。 4. 由于math.js处理的是大整数和大浮点数,所以在进行计算之前,需要将需要计算的数字转换成math.js支持的格式。可以使用`math.bignumber()`方法将数字转换成math.js支持的格式。 5. 最后,使用`math.format()`方法将计算结果转换成字符串格式,以避免出现科学计数法或多余的小数位。 举例来说,如果要解决0.1 + 0.2的计算精度问题,可以按照以下代码进行操作: ```javascript import math from 'mathjs' const addNumber = math.format(math.add(math.bignumber(0.1), math.bignumber(0.2))) console.log(addNumber) // 输出0.3 ``` 使用类似的方法,可以解决减法和除法的计算精度问题。请记住,在进行计算之前,将需要计算的数字转换成math.js支持的格式,然后使用相应的数学方法进行计算,并最后使用`math.format()`方法转换结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [vue使用mathjs解决前端计算精度不足问题](https://blog.csdn.net/qq_43555948/article/details/119885043)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值