自定义JS乘法运算误差解决!

在实际开发中遇到这样一个乘法公式:数量*单价=总价

像这样的浮点数列子: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 }

 

posted @ 2018-02-07 13:45  begrateful  阅读(803)  评论(0编辑  收藏  举报