Home > Web Front-end > JS Tutorial > body text

Detailed explanation of JavaScript floating point numbers and operation precision adjustment

高洛峰
Release: 2016-12-09 13:41:24
Original
1063 people have browsed it

JavaScript has only one number type, Number, and all numbers in JavaScript are represented in the IEEE-754 standard format. The precision issue with floating point numbers is not specific to JavaScript, as some decimals have an infinite number of digits represented in binary.

Decimal
0.1 0.0001 1001 1001 1001 …
0.2 0.0011 0011 0011 0011 …
0.3 0.0100 1100 1100 1100 …
0.4 0.0110 0110 0110 0110 …
0.5 0.1
0.6 0.1001 1001 1001 1001 …

So for example 1.1, The program actually cannot truly represent '1.1', but can only achieve a certain degree of accuracy. This is an unavoidable loss of precision: 1.099999999999999999

The problem is more complicated in JavaScript. Here are just some of the problems in Chrome Test data:

console.log(1.0-0.9 == 0.1)  //false
console.log(1.0-0.8 == 0.2)  //false
console.log(1.0-0.7 == 0.3)  //false
console.log(1.0-0.6 == 0.4)  //true
console.log(1.0-0.5 == 0.5)  //true
console.log(1.0-0.4 == 0.6)  //true
console.log(1.0-0.3 == 0.7)  //true
console.log(1.0-0.2 == 0.8)  //true
console.log(1.0-0.1 == 0.9)  //true
Copy after login

So how to avoid such non-bug problems of 1.0-0.9 != 0.1? The following is a commonly used solution. The calculation result is reduced in precision before judging the floating point operation result, because the precision reduction process will always be automatically rounded:

(1.0-0.9).toFixed(digits) // toFixed() 精度参数digits须在0与20之间
console.log(parseFloat((1.0-0.9).toFixed(10)) === 0.1)  //true
console.log(parseFloat((1.0-0.8).toFixed(10)) === 0.2)  //true
console.log(parseFloat((1.0-0.7).toFixed(10)) === 0.3)  //true
console.log(parseFloat((11.0-11.8).toFixed(10)) === -0.8)  //true
Copy after login

is written as a method:

//通过isEqual工具方法判断数值是否相等
function isEqual(number1, number2, digits){
 digits = digits == undefined? 10: digits; // 默认精度为10
 return number1.toFixed(digits) === number2.toFixed(digits);
}
console.log(isEqual(1.0-0.7, 0.3)); //true
//原型扩展方式,更喜欢面向对象的风格
Number.prototype.isEqual = function(number, digits){
 digits = digits == undefined? 10: digits; // 默认精度为10
 return this.toFixed(digits) === number.toFixed(digits);
}
console.log((1.0-0.7).isEqual(0.3)); //true
Copy after login

Next, let’s try the floating point operation,

console.log(1.79+0.12) //1.9100000000000001
console.log(2.01-0.12)  //1.8899999999999997
console.log(1.01*1.3)  //1.3130000000000002
console.log(0.69/10)   //0.06899999999999999
Copy after login

Solution:

//加法函数,用来得到精确的加法结果
//说明: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);
}
  
//减法函数,用来得到精确的减法结果
//说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的减法结果。
//调用:accSub(arg1,arg2)
//返回值:arg1减去arg2的精确结果
function accSub(arg1,arg2){
 var r1,r2,m,n;
 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));
 //last modify by deeka
 //动态控制精度长度
 n=(r1>=r2)?r1:r2;
 return ((arg1*m-arg2*m)/m).toFixed(n);
}
Copy after login

//除法函数,用来得到精确的除法结果
//说明: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);
}
<br>//验证一下:
console.log(accAdd(1.79, 0.12)); //1.91
console.log(accSub(2.01, 0.12)); //1.89
console.log(accDiv(0.69, 10));  //0.069<br>console.log(accMul(1.01, 1.3));  //1.313
Copy after login



Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!