你绝对想不到 toFixed()明明是数字的方法,结果转出来的是字符串,转字符串也就算了,结果,值还有可能不对。 我们正常理解的四舍五入,及时见5就入。但是你看看 对比之下发现 不管是 数字类型的 1.45 还是1.35 在toFixed()后都是1.4,结果还是字符串。什么原因呢
其实这也不错,为啥----
银行家算法:四舍六入五考虑,五后非0 就进一,五后为0看奇偶,五前为偶当舍去,五后为奇要进一。
银行家算法是一种最有代表性的 避免死锁的算法。 在避免死锁方法中允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。
例子如下。 所以这就造成了1.35 和1.45 在四舍五入后都是1.4 (银行家就是 5前奇进偶不进)
但是你看看toFixed(),假设总共有3块钱,我们用toFixed() 去分钱,结果就有问题。1.25和1.75 的时候就会多1毛前,如果在财务中,这1毛钱就翻天了。
好了继续说一下toFixed()(全TM是字符串), toFixed它是一个四舍六入 五成双的诡异的方法(也叫银行家算法), "四舍六入五成双"含义:对于位数很多的近似数,当有效位数确定后,其后面多余的数字应该舍去,只保留有效数字最末一位,这种修约(舍入)规则是“四舍六入五成双”,也即“4舍6入5凑偶”这里“四”是指≤4 时舍去,"六"是指≥6时进上,"五"指的是根据5后面的数字来定,当5后有数时,舍5入1;当5后无有效数字时,需要分两种情况来讲:①5前为奇数,舍5入1;②5前为偶数,舍5不进。(0是偶数) 但是 经过我的测试发现,在chorme下面(最新版),并没有完全遵守这个规则,尤其是5的后面没有数字的时候,不是这么判断的,如下: 继续先看例子 跟上边的测试例子有冲突
var b = 1.335
console.log(b.toFixed(2)) // "1.33" 是不是以为是1.34
var b = 1.345
console.log(b.toFixed(2)) // "1.34" 是不是以为是1.35
var b = 1.355
console.log(b.toFixed(2)) // "1.35" 是不是以为是1.36
var b = 1.365
console.log(b.toFixed(2)) // "1.36" 是不是以为是1.37
var b = 1.375
console.log(b.toFixed(2)) // "1.38"
var b = 1.385
console.log(b.toFixed(2)) // "1.39"
可以发现在chorme下没有完全去遵循这个规律,或许它有自己的算法,但是毕竟它没有遵循通用的银行家算法,所以
tofixed这个方法在涉及到金钱计算的业务中还是少用, 最好别用,否则可能会出大问题!
自己的做法就是根据 精确位数 来取小数点后的数,然后判断精确位是大于4还是小于等于4,上代码吧,不说了:
假设做做到 是两位小数,最少就是取整,不留小数
function moneySwitch(money, precision){ // precision是需要精确的位数,如百分位就是2
var result = 0;
//先进行一个千分位的四舍五入,保证3.0999这种情况在保留一位小数的时候能是对的,这一位可以这么做没什么问题
var money = parseFloat(money).toFixed(3);
try{
var int_part = money.split(".")[0], // 小数点前的整数
point_num = money.split(".")[1], // 取小数点后面的小数
precision_num = point_num[3-precision];
if(precision_num>4){//五入的情况
if(precision==1){
point_num = parseInt(point_num)+10+"";
if(point_num.length>3){//说明往整数位进1
int_part = parseInt(int_part)+1+"";
point_num = point_num[1]+point_num[2];
}else{
point_num = point_num[0]+point_num[1];
}
result = parseFloat(int_part+"."+point_num);
}else if(precision==2){
point_num = parseInt(point_num)+100+"";
if(point_num.length>3){//说明往整数位进1
int_part = parseInt(int_part)+1+"";
point_num = point_num[1];
}else{
point_num = point_num[0];
}
result = parseFloat(int_part+"."+point_num);
}else if(precision==3){
int_part = parseInt(int_part)+1+"";
point_num = 0;
}
result = parseFloat(int_part+"."+point_num);
}else{//四舍的情况
if(precision==1){
point_num = point_num[0]+point_num[1];
}else if(precision==2){
point_num = point_num[0];
}else if(precision==3){
point_num = 0;
}
result = parseFloat(int_part+"."+point_num);
}
}
catch(e){
return parseFloat(money).toFixed(2);//如果过程中有出错就tofixed代替为解决
}
return result;
}
真心用了toFixed()后坑死我了。
把toFixed() 转换成数字类型的方法
但是这些后期也会有问题。
推荐写法 Math.round(x) 函数返回一个数字四舍五入后最接近的整数。 Math.round( x * 100) / 100 但是发现这个只能是两位小数。
|