首页 > 其他分享 >js小数运算出现多位小数如何解决

js小数运算出现多位小数如何解决

时间:2023-11-08 13:33:04浏览次数:40  
标签:运算 arg1 arg2 Number js try toString 小数

为什么操作小数会出现误差?

浮点数值的最高进度是17位小数,但在进行运算的时候其精确度却远远不如整数;整数在进行运算的时候都会转成10进制; 而Java和JavaScript中计算小数运算时,都会先将十进制的小数换算到对应的二进制,一部分小数并不能完整的换算为二进制,这里就出现了第一次的误差。待小数都换算为二进制后,再进行二进制间的运算,得到二进制结果。然后再将二进制结果换算为十进制,这里通常会出现第二次的误差。

所以(0.1+0.2)!=03

解决方式:

除法函数,用来得到精确的除法结果
说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
调用:accDiv(arg1,arg2)
返回值:arg1除以arg2的精确结果

function accDiv(arg1,arg2){  
  var t1=0,t2=0,r1,r2;  
  try{
    t1=arg1.toString().split(".")[1].length;  }catch(e){}  try{
     t2=arg2.toString().split(".")[1].length;  }catch(e){}
  with(Math){    r1=Number(arg1.toString().replace(".","")); 
     r2=Number(arg2.toString().replace(".","")); 
    return (r1/r2)*pow(10,t2-t1);    }}

给Number类型增加一个div方法,调用起来更加方便。

Number.prototype.div = function (arg){  
  return accDiv(this, arg);
}

乘法函数,用来得到精确的乘法结果
说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
调用:accMul(arg1,arg2)
返回值:arg1乘以arg2的精确结果

function accMul(arg1,arg2){  
var m=0,s1=arg1.toString(),
s2=arg2.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类型增加一个mul方法,调用起来更加方便。

Number.prototype.mul = function (arg){  
    return accMul(arg, this);
}

加法函数,用来得到精确的加法结果

说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
调用:accAdd(arg1,arg2)
返回值:arg1加上arg2的精确结果

function accAdd(arg1,arg2){ 
var r1,r2,m;  
try{
  r1 = arg1.toString().split(".")[1].length;
}catch(e){r1=0}  try{
  r2 = arg2.toString().split(".")[1].length;}catch(e){r2=0}m = Math.pow(10,Math.max(r1,r2));
return (arg1*m+arg2*m)/m;
}

给Number类型增加一个add方法,调用起来更加方便。

Number.prototype.add = function (arg){  
    return accAdd(arg,this);
}

在你要用的地方包含这些函数,然后调用它来计算就可以了。
比如你要计算:7*0.8 ,则改成 (7).mul(8) 
其它运算类似,就可以得到比较精确的结果。

解决方式二:

比较常用的办法,toFixed(),toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。在我们计算的结果后面加上这个方法就OK了;但是对精度会有一丝影响,如果精度要求不高的话推荐使用。

============================

一个有趣的测试:

0.1+0.2 == 0.3 //false
顿时郁闷,好吧!原来0.1+0.2变成:0.30000000000000004
再来一个 2.4/0.8 =>2.9999999999999996 没办法换种方式,都转换成整数 (2.4 * 100)/(0.8 * 100)
10.22 现在要减去 0.11 结果值又出现了很多的小数 10.110000000000001,然后我就用了 toFixed 方法来过滤小数,但是不知道跟前面那种转换成整数后再执行哪种效率高,好!还是试下再说吧!

 

查了一些资料,一是 JavaScript 浮点数计算的 Bug,另一个是和计算机最终转换成二进制计算有关系。

解决方法:
解决这种问题两种方法,第一种就是利用JavaScript 的toFixed(n) 方法,直接获取N 位小数,这种方法在数据精度上会有一些问题。如果数据精度要求不高的话可以使用。

alert((0.1 + 0.2).toFixed(1));

第二种方法就是自己编写运算方法。以下是自定义加法函数,使用此方法进行相加会避免上面问题。

//自定义加法运算
function addNum (num1, num2) {
 var sq1,sq2,m;
 try {
  sq1 = num1.toString().split(".")[1].length;
 }
 catch (e) {
  sq1 = 0;
 }
 try {
  sq2 = num2.toString().split(".")[1].length;
 }
 catch (e) {
  sq2 = 0;
 }
 m = Math.pow(10,Math.max(sq1, sq2));
 return (num1 * m + num2 * m) / m;
}
alert(addNum(0.1, 0.2));

当然,简单一点也可以写成:alert((num * 3 + 10 * 3) /3); 这样也不会出现 N 多位小数。
alert((num * 3 + 10 * 3) /3); 与 alert(num + 10); 这两种写法计算机在底层转换成二进制运算是有区别的,或许这就是出现上述问题的原因

标签:运算,arg1,arg2,Number,js,try,toString,小数
From: https://www.cnblogs.com/lyp404/p/17817182.html

相关文章

  • Shell中的数值运算
    使用expr、$[]、let等整数运算工具:进行四则运算及求模结果使用bc实现小数运算操作h1整数运算工具1.1使用expr命令乘法操作应采用\*转义,避免被作为Shell通配符;参与运算的整数值与运算操作符之间需要以空格分开,引用变量时必须加$符号。首先随便定义变量比如a=10,b=20,然后计算a与b......
  • SQL Server 2005透视表运算符PIVOT应用示例
    SQLServer2005行列转换 有用SQL写过交叉报表的,往往都比较头痛,还好现在SQL2005中提供了新的PIVOT操作符,可以很简单地写出交叉数据查询。正好前两天在研究ORACLE最新的11G版本提供的新特性,发现ORACLE11G也同样推出这个新PIVOT,而且语法格式也几乎是一样的,呵,看来这些主流的数据库都......
  • 赋值运算符,比较运算符,逻辑运算符的应用
    print('-----------赋值运算------------')a=20b=30a=a+b#赋值运算:此处的a是经过20+30后再次赋值给aprint(a)#运行接轨a=50a+=b#这里的运算相当于a=a+b其运算结果为50+30=80print(a)#结果为80a-=b#这里的运算相当于a=a-b其运算结果为80-30......
  • C语言程序设计 运算符的优先级与结合性
     C运算符的优先级与结合优先级运算符含义参与运算对象的数目结合方向 1()[]->.圆括号运算符下标运算符指向结构体成员运算符结构体成员运算符双目运算符双目运算符双目运算符自左至右2!~+......
  • js 判空
    JSON.stringifyJSON.stringify 方法可以使对象序列化,转为相应的JSON格式。constobj={};console.log(JSON.stringify(obj)==='{}')//true缺点:如果存在 undefined、任意的函数以及symbol值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出......
  • gjson
    1.通配符‘#’1.1例子在gjson中,井号#是一个通配符,用于匹配JSON数组中的所有元素。在你的查询中,#用于匹配NetworkAdapterComplexes数组中的每个元素,然后继续沿着JSON结构的路径。让我们解释你的查询的各个部分:NetworkAdapterComplexes.#:这部分使用#通配符,匹配......
  • Node.js如何处理多个请求?
    Node.js如何处理多个请求?前言在计算机科学领域,关于并发和并行的概念经常被提及。然而,这两个术语常常被混为一谈,导致很多人对它们的理解存在着很多混淆。本文小编将通过对并发和并行的深入解析,帮助读者更好地理解它们之间的不同特点和应用场景。同时,文章还将介绍Node.js如何高效......
  • js返回未来或过去7天等时间合集(任意日期区间合集)
    /***时间前后向前推算时间集合*@param{string:before|after}timebd:获取时间往后推,还是往前推,*@param{boole}haveCurrentDay:包不包含当天时间,*@param{number}Days:计算几天的时间,*@param{string:"2023-11-02"}timing:指定不指定当天的日期*@return{array}......
  • @RequestBody接收Json参数 用自定义注解对Vo对象中Date类型日期格式校验
    @RequestBody接收Json参数|用自定义注解对Vo对象中Date类型日期格式校验问题描述昨天测试的同事测试接口的时候,测试出来一个Date类型校验问题。要求输入的日期格式是:yyyy-MM-ddHH:mm:ss,Vo中使用的注解如下:@DateTimeFormat(pattern=”yyyy-MM-ddHH:mm:ss”)测试同事输入下面两种......
  • ES6 module和CommonJS的区别
    ES6module和CommonJS的区别主要有5点ES6module是编译时导出接口,CommonJS是运行时导出对象。ES6module输出的值的引用,CommonJS输出的是一个值的拷贝。ES6module语法是静态的,CommonJS语法是动态的。ES6module导入模块的是只读的引用,CommonJS导入的是可变的,是一个普通的变......