淘宝客网站需要备案吗/东莞外贸推广公司
首先是toFixed方法,原本的方法有一些误差,小数点部分不是真正的四舍五入
例如console.log(1.335.toFixed(2)) //1.33
所以有必要重写一下:
const toFixed = function (myNum,s) {// Math.pow(10, s) =>10的s次方// Math.round=>整数后面的第一个小数数字四舍五入=>例如0.0055501*10^2=>0.5xxx=>1// 1/100=>0.01myNum = (Math.round(myNum * Math.pow(10, s)) / Math.pow(10, s)).toString();// 匹配'.'的字符串的下标let index = myNum.indexOf(".");// 当'.'不存在且保留小数位数大于0时=>myNum是整数时,直接加'.',再按照小数位数用0占位if (index === -1 && s > 0) {myNum += ".";for (let i = 0; i < s; i++) {myNum += "0";}} else {// '.'之后的第一个字符所在的下标index = myNum.length - 1 - index;// s - index若大于等于1就加'0'for (let i = 0; i < (s - index); i++) {myNum = myNum + "0";}}return myNum;
} let num = '0.0055501'
console.log(toFixed(parseFloat(num),2))//0.01
console.log(toFixed(parseFloat(num),3))//0.006
console.log(toFixed(parseFloat(num),8))//0.00555010console.log(toFixed(parseFloat(0.005 * 0.22),2))//0.00
之所以传参的时候还要使用parseFloat,因为JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)。容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算!!
由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
注意:
1.使用Math.round方法将浮点数四舍五入变成整数的特点切题
2.Math.round(xx浮点数*(10^s)/(10^s)) 得到四舍五入的数字(可能是整数,也可能是浮点数)
3.然后按照要求保留s位小数位数,不足位数的补0
但是,事实的情况是JavaScript的加减乘除有精度缺失的问题,这里主要讲除法计算方法的优化:
// 针对除不尽的除数做处理--主题思想: 先乘以10^n,这样除以除数的时候数字变大了,精度就提高了,然后再除以10^n拿到原本的结果
export const divided = (myNum: number|string, dividedNum:number = 1) => {const num1 = String(myNum).replace('.','');const num2 = String(dividedNum).replace('.','');const len1 = String(myNum).split('.')[1].length;const len2 = String(dividedNum).split('.')[1].length;myNum = ((Number(num1) / Number(num2)))*Math.pow(10, len2 - len1);return isNaN(Number(myNum)) ? 0: Number(myNum);
}
这样得到尽量精确的原始数字,再使用上述的toFixed函数结果就尽可能精确了.
eg:
使用控制台: 3824.205/11/11 => 使用toFixed(3824.205/11/11, 2) => 31.60
而若是3824.205/121 =>保留2位小数却是31.61
也就是除法尽量少,使用运算法则改变运算顺序,但感觉还是有点担心,有小数的情况呢?所以还是使用divided函数先做一下数字的处理:
使用toFixed(divided(3824.205, 11*11), 2) => 31.61
然后使用手机计算机比对计算结果(注意四舍五入)
更为精确
至于乘法: 主要考虑小数的乘法
逻辑: 先把每个乘数*10^n变为整数=>s1.replace('.', '')比较高效,其他方法不赘述 =>这样自然都是整数相乘,再除以10^n得到尽量精确的结果:
// 乘法函数
export const accMul = (arg1:number, arg2:number, arg3:number = 1) => {let m = 0;let s1 = String(arg1);let s2 = String(arg2);let s3 = String(arg3);try {m += s1.split('.')[1].length;} catch(e) {}try {m += s2.split('.')[1].length;} catch(e) {}try {m += s3.split('.')[1].length;} catch(e) {}return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) * Number(s3.replace('.', ''))/ Math.pow(10, m);
}
虽然以上方法能够解决大多数问题,但是也会有特殊情况:
使用浏览器控制台输入Math.round(69.945*Math.pow(10,2))/Math.pow(10,2)
结果居然是69.94!!!
使用浏览器控制台输入Math.round(79.945*Math.pow(10,2))/Math.pow(10,2)
结果居然是79.94!!!
完全不是四舍五入的结果,这样看来上面的方法还是有局限性的
所以还是更细致地判断比较好:
// 注意:此为直接截取小数点后s位的方法,非四舍五入--数字字符串--'2.00'
export function toFixedFloor(myNum: number | string, s: number) {myNum = Number(myNum);if(isNaN(myNum)) return `0.${'0'.repeat(s)}`;myNum = (Math.floor(myNum * Math.pow(10, s)) /Math.pow(10, s)).toString();return addZeroStr(myNum, s);
}// 保留小数位数的数字不足的加0补足
export const addZeroStr = (myNum: number | string, s: number) => {myNum = String(getNum(myNum));// 匹配。字符串下标let index = myNum.indexOf('.');if (index === -1 && s > 0) {myNum += `.${'0'.repeat(s)}`;} else {index = myNum.length - 1 - index;myNum += `${'0'.repeat(s - index)}`;}return myNum;
}// 四舍五入--数字字符串--'2.05'
export function toFixedRound(myNum: number | string, s: number) {const myNewNum:string = toFixedFloor(myNum, s+1);// console.log(myNum, '四舍五入!!!!!!', 'hhhhhhhhhhhhhhhhhhhhhh')// 小数四舍五入myNum = String(getNum(myNewNum));const numArr:any[] = myNum.split('.');// 保留x位小数,从x+1位小数是否大于等于5判断const lastIdx:number = myNum.length-1;const num1:string = myNum.substring(0, lastIdx);if(numArr.length>1&&numArr[1].length>s) {if(Number(myNum[lastIdx])>=5) {const num:number = Number(num1)*Math.pow(10,num1.split('.')[1].length) + 1;const newNum:string = String(num / Math.pow(10,num1.split('.')[1].length));myNum = newNum.substring(0, newNum.length);}else if(Number(myNum[lastIdx])<5) {myNum = myNum.substring(0, lastIdx);}return myNum;}else {return myNewNum.substring(0, myNewNum.length-1);}
};export const getNum = (myNum:any) => isNaN(Number(myNum)) ? 0: Number(myNum);