产品经理:优惠金额只入不舍,支付金额只舍不入...
前言
当前做的项目是一个售卖会员的平台。其中涉及到优惠券、支付金额等。
优惠券分为:折扣券(n折)、抵扣券(减x元)
需求
优惠金额、支付金额都需要保留两位小数。
优惠金额只入不舍,比如18.811元,显示为:18.82元。这样看起来,优惠的相对多一些
支付金额只舍不入,比如18.888元,显示为:18.88元。
从产品角度来讲,这个设计相当人性化。
实现
/**
* 金额计算
* @param {number} a sku原始价格
* @param {number} b 优惠券金额/折扣
* @param {string} mathFunc 四舍五入:round/ceil/floor
* @param {string} type 计算方式默认减法
* @param {digits} type 精度,默认两位小数
* */
export function numbleCalc(a, b,mathFunc='round', type = '-',digits=2) {
var getDecimalLen = num =>{
return num.toString().split('.')[1] ? num.toString().split('.')[1].length : 0;
}
//将小数按照一定的倍数转换成整数数
var floatToInt = (num,numlen,maxlen)=>{
var numInt = num.toString().replace('.', '');
if(numlen==maxlen)return +numInt;
return numInt * (10**(maxlen-numlen))
}
var c;
//获取2个数字中,最长的小数位数
var aLen = getDecimalLen(a);
var bLen = getDecimalLen(b);
var decimalLen = aLen>bLen?aLen:bLen;
var mul = decimalLen>0?(10 ** decimalLen):1;
//转换成整数
var aInteger = floatToInt(a,aLen,decimalLen)
var bInteger = floatToInt(b,bLen,decimalLen)
if(type=='-'){
c = (aInteger - bInteger)/mul;
}else if(type=='*'){
c = aInteger * bInteger/mul/mul;
}
c = digits==0?c : Math.round(c * (10 ** digits));
if(mathFunc=='floor'){
c= Math.floor(c);
}else if(mathFunc=='ceil'){
c= Math.ceil(c);
}else {
c= Math.round(c);
}
return digits==0?c : c/(10**digits);
}
整体思路:获取两个数字之间最大的小数位,先取整再计算。
不直接进行计算,是因为存在0.1+0.2!=0.3的情况,具体原因可以看下文章下方的参考链接,写的很详细。
- Math.ceil() 总是向上舍入,并返回大于等于给定数字的最小整数。
- Math.floor() 函数总是返回小于等于一个给定数字的最大整数。
- Math.round() 四舍五入
【重点】小数位取整:我之前的写法原来是错误的
我一直以来也是这种形式,预想的是直接乘100变成整数,但是出现了以下情况
19.9 * 100 = 1989.9999999999998
5.02 * 100 = 501.99999999999994
可以看到,出现了意料之外的结果!!
最后采用的方案是:将小数转成字符串,再将小数点替换成空格
//将小数按照一定的倍数转换成整数数
var floatToInt = (num,numlen,maxlen)=>{
var numInt = num.toString().replace('.', '');
if(numlen==maxlen)return +numInt;
return numInt * (10**(maxlen-numlen))
}
总结
省流:将小数点替换成空格,变成整数,再进行相应计算。
封装的这个函数,只考虑了当前业务场景,未兼容一些边界值情况。
- 大金额计算问题
- 计算方式:加法、除法未做处理
参考
作者:前端大明
来源:juejin.cn/post/7341210909069770792
来源:juejin.cn/post/7341210909069770792