方案来自网络,实现简单,便于做加减乘除使用,由于项目临时要用记录下
如需要更加复杂的计算类库,可以考虑 math.js等知名类库
假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情请点击http://106.12.206.16:8080/qingruihappy/index.html
一,解决方案
1 /** 2 * floatTool 包含加减乘除四个方法,能确保浮点数运算不丢失精度 3 * 4 * 我们知道计算机编程语言里浮点数计算会存在精度丢失问题(或称舍入误差),其根本原因是二进制和实现位数限制有些数无法有限表示 5 * 以下是十进制小数对应的二进制表示 6 * 0.1 >> 0.0001 1001 1001 1001…(1001无限循环) 7 * 0.2 >> 0.0011 0011 0011 0011…(0011无限循环) 8 * 计算机里每种数据类型的存储是一个有限宽度,比如 JavaScript 使用 64 位存储数字类型,因此超出的会舍去。舍去的部分就是精度丢失的部分。 9 * 10 * ** method ** 11 * add / subtract / multiply /divide 12 * 13 * ** explame ** 14 * 0.1 + 0.2 == 0.30000000000000004 (多了 0.00000000000004) 15 * 0.2 + 0.4 == 0.6000000000000001 (多了 0.0000000000001) 16 * 19.9 * 100 == 1989.9999999999998 (少了 0.0000000000002) 17 * 18 * floatObj.add(0.1, 0.2) >> 0.3 19 * floatObj.multiply(19.9, 100) >> 1990 20 * 21 */ 22 var floatTool = function() { 23 24 /* 25 * 判断obj是否为一个整数 26 */ 27 function isInteger(obj) { 28 return Math.floor(obj) === obj 29 } 30 31 /* 32 * 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100 33 * @param floatNum {number} 小数 34 * @return {object} 35 * {times:100, num: 314} 36 */ 37 function toInteger(floatNum) { 38 var ret = {times: 1, num: 0} 39 if (isInteger(floatNum)) { 40 ret.num = floatNum 41 return ret 42 } 43 var strfi = floatNum + '' 44 var dotPos = strfi.indexOf('.') 45 var len = strfi.substr(dotPos+1).length 46 var times = Math.pow(10, len) 47 var intNum = parseInt(floatNum * times + 0.5, 10) 48 ret.times = times 49 ret.num = intNum 50 return ret 51 } 52 53 /* 54 * 核心方法,实现加减乘除运算,确保不丢失精度 55 * 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除) 56 * 57 * @param a {number} 运算数1 58 * @param b {number} 运算数2 59 * @param digits {number} 精度,保留的小数点数,比如 2, 即保留为两位小数 60 * @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide) 61 * 62 */ 63 function operation(a, b, op) { 64 var o1 = toInteger(a) 65 var o2 = toInteger(b) 66 var n1 = o1.num 67 var n2 = o2.num 68 var t1 = o1.times 69 var t2 = o2.times 70 var max = t1 > t2 ? t1 : t2 71 var result = null 72 switch (op) { 73 case 'add': 74 if (t1 === t2) { // 两个小数位数相同 75 result = n1 + n2 76 } else if (t1 > t2) { // o1 小数位 大于 o2 77 result = n1 + n2 * (t1 / t2) 78 } else { // o1 小数位 小于 o2 79 result = n1 * (t2 / t1) + n2 80 } 81 return result / max 82 case 'subtract': 83 if (t1 === t2) { 84 result = n1 - n2 85 } else if (t1 > t2) { 86 result = n1 - n2 * (t1 / t2) 87 } else { 88 result = n1 * (t2 / t1) - n2 89 } 90 return result / max 91 case 'multiply': 92 result = (n1 * n2) / (t1 * t2) 93 return result 94 case 'divide': 95 return result = function() { 96 var r1 = n1 / n2 97 var r2 = t2 / t1 98 return operation(r1, r2, 'multiply') 99 }() 100 } 101 } 102 103 // 加减乘除的四个接口 104 function add(a, b) { 105 return operation(a, b, 'add') 106 } 107 function subtract(a, b) { 108 return operation(a, b, 'subtract') 109 } 110 function multiply(a, b) { 111 return operation(a, b, 'multiply') 112 } 113 function divide(a, b) { 114 return operation(a, b, 'divide') 115 } 116 117 // exports 118 return { 119 add: add, 120 subtract: subtract, 121 multiply: multiply, 122 divide: divide 123 } 124 }();
使用方法:
floatTool.add(a,b);//相加 floatTool.subtract(a,b);//相减 floatTool.multiply(a,b);//相乘 floatTool.divide(a,b);//相除
积跬步,至千里
二,案例中的成功应用
1 var floatTool = function() { 2 3 /* 4 * 判断obj是否为一个整数 5 */ 6 function isInteger(obj) { 7 return Math.floor(obj) === obj 8 } 9 10 /* 11 * 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100 12 * @param floatNum {number} 小数 13 * @return {object} 14 * {times:100, num: 314} 15 */ 16 function toInteger(floatNum) { 17 var ret = {times: 1, num: 0} 18 if (isInteger(floatNum)) { 19 ret.num = floatNum 20 return ret 21 } 22 var strfi = floatNum + '' 23 var dotPos = strfi.indexOf('.') 24 var len = strfi.substr(dotPos+1).length 25 var times = Math.pow(10, len) 26 var intNum = parseInt(floatNum * times + 0.5, 10) 27 ret.times = times 28 ret.num = intNum 29 return ret 30 } 31 32 /* 33 * 核心方法,实现加减乘除运算,确保不丢失精度 34 * 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除) 35 * 36 * @param a {number} 运算数1 37 * @param b {number} 运算数2 38 * @param digits {number} 精度,保留的小数点数,比如 2, 即保留为两位小数 39 * @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide) 40 * 41 */ 42 function operation(a, b, op) { 43 var o1 = toInteger(a) 44 var o2 = toInteger(b) 45 var n1 = o1.num 46 var n2 = o2.num 47 var t1 = o1.times 48 var t2 = o2.times 49 var max = t1 > t2 ? t1 : t2 50 var result = null 51 switch (op) { 52 case 'add': 53 if (t1 === t2) { // 两个小数位数相同 54 result = n1 + n2 55 } else if (t1 > t2) { // o1 小数位 大于 o2 56 result = n1 + n2 * (t1 / t2) 57 } else { // o1 小数位 小于 o2 58 result = n1 * (t2 / t1) + n2 59 } 60 return result / max 61 case 'subtract': 62 if (t1 === t2) { 63 result = n1 - n2 64 } else if (t1 > t2) { 65 result = n1 - n2 * (t1 / t2) 66 } else { 67 result = n1 * (t2 / t1) - n2 68 } 69 return result / max 70 case 'multiply': 71 result = (n1 * n2) / (t1 * t2) 72 return result 73 case 'divide': 74 return result = function() { 75 var r1 = n1 / n2 76 var r2 = t2 / t1 77 return operation(r1, r2, 'multiply') 78 }() 79 } 80 } 81 82 // 加减乘除的四个接口 83 function add(a, b) { 84 return operation(a, b, 'add') 85 } 86 function subtract(a, b) { 87 return operation(a, b, 'subtract') 88 } 89 function multiply(a, b) { 90 return operation(a, b, 'multiply') 91 } 92 function divide(a, b) { 93 return operation(a, b, 'divide') 94 } 95 96 // exports 97 return { 98 add: add, 99 subtract: subtract, 100 multiply: multiply, 101 divide: divide 102 } 103 }(); 104 105 106 var key_OrdinaryRate=$("#key_OrdinaryRate").val(); 107 var key_OrdinaryRate_x=floatTool.divide(key_OrdinaryRate,100);//相除 108 $("#key_OrdinaryRate_x").val(key_OrdinaryRate_x); 109 110 111 var key_DebitOrdinaryRate=$("#key_DebitOrdinaryRate").val(); 112 var key_DebitOrdinaryRate_x=floatTool.divide(key_DebitOrdinaryRate,100);//相除 113 $("#key_DebitOrdinaryRate_x").val(key_DebitOrdinaryRate_x);