老实说在今天之前,我对javascript的浮点数运算毫无认识,觉得应该和实际运算中一样,然而,有些事情往往会出人意料。
先看一组数据:
0.1 + 0.11 = 0.21000000000000002
0.2 * 3 = 0.6000000000000001
0.7 / 10 = 0.06999999999999999
你相信吗?如果不信,那么立即打开firefox浏览器测试吧。有一点可以确信,你看到测试结果的表情,一定先是惊讶,后来是迷惑。
这里有几个demo,再来看看出现浮点数运算bug的概率,猛击之:加法、乘法、除法
对于这样的结果,我不知道是怎么产生的,但是既然是bug,就一定是可以hack的,思路很简单,先把所有的运算数转成int型(表达不准确,javascript的没有int、float之分),计算出两个运算数的小数点后的位数,再进行适当的运算,就可以得到原始的我们期望看到的结果了。代码如下:
加法运算:
- function add(num1,num2){
- var reg = /\./i;
- if(!reg.test(num1) && !reg.test(num2)){
- return num1 * num2;
- }
- var r1 = 0, r2 = 0, m;
- var str1 = num1.toString(), str2 = num2.toString();
- if(str1.indexOf('.')>-1){
- r1 = str1.split('.')[1].length;
- }
- if(str2.indexOf('.')>-1){
- r2 = str2.split('.')[1].length;
- }
- m = Math.pow(10,Math.max(r1,r2));
- return (mul(num1,m) + mul(num2,m)) / m;
- }
乘法运算:
- function mul(num1,num2){
- var reg = /\./i;
- if(!reg.test(num1) && !reg.test(num2)){
- return num1 * num2;
- }
- var len = 0, str1 = num1.toString(), str2 = num2.toString();
- if(str1.indexOf('.')>=0){
- len += str1.split('.')[1].length;
- }
- if(str2.indexOf('.')>=0){
- len += str2.split('.')[1].length;
- }
- return Number(str1.replace('.','')) * Number(str2.replace('.','')) / Math.pow(10,len);
- }
除法运算:
- function div(num1,num2){
- var reg = /\./i;
- if(!reg.test(num1) && !reg.test(num2)){
- return num1 * num2;
- }
- var len1 = 0, len2 = 0;
- var str1 = num1.toString(), str2 = num2.toString();
- //计算位数差
- if(str1.indexOf('.')>-1){
- len1 = str1.split('.')[1].length;
- }
- if(str2.indexOf('.')>-1){
- len2 = str2.split('.')[1].length;
- }
- return mul(Number(str1.replace('.','')) / Number(str2.replace('.','')),Math.pow(10,len2-len1));
- }
