在实际开发中遇到这样一个乘法公式:数量*单价=总价
像这样的浮点数列子:200*8.2,JS算出的结果是:
像这种浮点数的乘法计算就会有误差,我们需要得到准确的值应该是:1640,与我们后台C#计算结果要一致。
这里我们采用两种方式来解决。
1:乘数和被乘数同时扩大10000倍。因为金额的最小单位也就是厘。然后结果在除以100000000,公式是:(2000000*82000)/100000000
这种方式如果小数位要求越高,也还是有误差的,下面再说。
2:自定义乘法,这种方式利用小学的计算公式,拆分计算,目的是避免float*float,而是使用int*float ,公式是:200*8.2 拆分就是:(200*8+200*0.2)+(0*8+0*0.2)
具体实现代码如下:
1 /** 2 * 将小数拆分为整数+小数形式返回数组 3 * @method 4 * @param {String} 字符串数字 5 * @return {Array} 返回数组 数组下表[0]部分为是否成功,数组[1]部分为整数,数组[2]为小数 6 */ 7 function getDecimal(num) { 8 var numArray = new Array(); 9 // 将输入的内容转为float类型(如果是小数为了保留小数部分) 10 if (checkNumber(num)) { 11 var isFloat = parseFloat(num); 12 13 if (isFloat === 0) { 14 numArray[0] = true; 15 numArray[1] = parseFloat("0.0");// 整数部分 16 numArray[2] = parseFloat("0.0"); 17 } else { 18 // 是数字类型 19 numArray[0] = true; 20 //判断是否有小数 21 if (isFloat.toString().indexOf(".") < 0) { 22 numArray[1] = isFloat;// 整数部分 23 numArray[2] = parseFloat("0.0"); 24 } else { 25 var numArr = isFloat.toString().split("."); 26 numArray[1] = parseInt(numArr[0]);// 整数部分 27 numArray[2] = parseFloat('0.' + numArr[1]);// 小数部分 28 } 29 } 30 } else { 31 numArray[0] = false; 32 } 33 return numArray; 34 } 35 36 37 /** 38 * 解决小数精度问题 39 * @param {*数字 } a 40 * @param {*数字 } b 41 * @param {*符号 } sign 42 * fixedFloat(0.3, 0.2, '-') 43 * 参考:https://my.oschina.net/cjlice/blog/1616682 44 */ 45 46 function fixedFloat(a, b, sign) { 47 function handle(x) { 48 var y = String(x); 49 var p = y.lastIndexOf('.'); 50 if (p === -1) { 51 return [y, 0]; 52 } else { 53 return [y.replace('.', ''), y.length - p - 1]; 54 } 55 } 56 // v 操作数1, w 操作数2, s 操作符, t 精度 57 function operate(v, w, s, t) { 58 switch (s) { 59 case '+': 60 return (v + w) / t; 61 case '-': 62 return (v - w) / t; 63 case '*': 64 return (v * w) / (t * t); 65 case '/': 66 return (v / w); 67 } 68 } 69 70 var c = handle(a); 71 var d = handle(b); 72 var k = 0; 73 74 if (c[1] === 0 && d[1] === 0) { 75 return operate(+c[0], +d[0], sign, 1); 76 } else { 77 k = Math.pow(10, Math.max(c[1], d[1])); 78 if (c[1] !== d[1]) { 79 if (c[1] > d[1]) { 80 d[0] += padding0(c[1] - d[1]); 81 } else { 82 c[0] += padding0(d[1] - c[1]); 83 } 84 } 85 return operate(+c[0], +d[0], sign, k); 86 } 87 } 88 89 // 补0 90 function padding0(p) { 91 var z = ''; 92 while (p--) { 93 z += '0'; 94 } 95 return z; 96 } 97 98 // 加 99 function plus(a, b) { 100 return fixedFloat(a, b, '+'); 101 } 102 // 减 103 function minus(a, b) { 104 return fixedFloat(a, b, '-'); 105 } 106 // 乘 107 function multiply(a, b) { 108 return fixedFloat(a, b, '*'); 109 } 110 // 除 111 function division(a, b) { 112 return fixedFloat(a, b, '/'); 113 } 114 115 116 /** 117 * 自定义加法 118 * @method 119 * @param {String} 字符串 120 * @param {String} 字符串 121 * @return {number} 返回计算结果 122 */ 123 function addition(numOne, numTwo) { 124 return plus(numOne, numTwo); 125 } 126 127 /** 128 * 自定义乘法 129 * @method 130 * @param {String} 字符串 131 * @param {String} 字符串 132 * @return {number} 返回计算结果 133 */ 134 function multiplication(numOne, numTwo) { 135 return multiply(numOne, numTwo); 136 }; 137 138 139 /** 140 * 判断输入是否是数字(包含小数正负) 141 * @method 142 * @param {String} 字符串 143 * @return {true/false} 返回true/false 144 */ 145 function checkNumber(theObj) { 146 var reg = /^(\-|+)?d+(.d+)?$/; 147 if (reg.test(theObj)) { 148 return true; 149 } 150 return false; 151 }