问题:四舍五入保留三位小数时 精度不准确 如 num=3.3245 得到的结果却确3.324
原因解析:
在网上查了些资料才知道,
1、在JS内部所有的计算都是以二进制方式计算的。
2、JS内部无法无限制保存二进制数值的长度。(最长52位)
我们的计算机底层都是0和1,当然,计算机也不能保留无限长(无限大)的东西。知道了以上两点,应该就不难理解了为什么JS在计算超大的数值的时候,会出现问题了,那么为什么计算很小浮点数的时候也会出问题呢,因为在JS内部,浮点数也是用很长很长的二进制表示的。
解决办法:
一、自定义方法
function round(num,iCount) {
// iCount 保留几位小数
var srcValue = num;
var zs = true;
//判断是否是负数
if ( srcValue < 0 )
{
srcValue = Math.abs(srcValue);
zs = false;
}
var iB = Math.pow(10, iCount);
//有时乘100结果也不精确
var value1 = srcValue * iB;
var anumber = new Array();
var anumber1 = new Array();
var fvalue = value1;
var value2 = value1.toString();
var idot = value2.indexOf(".");
//如果是小数
if ( idot != -1 )
{
anumber = srcValue.toString().split(".");
//如果是科学计数法结果
if ( anumber[1].indexOf("e") != -1 )
{
return Math.round(value1) / iB;
}
anumber1 = value2.split(".");
if ( anumber[1].length <= iCount )
{
return parseFloat(num,10);
}
var fvalue3 = parseInt(anumber[1].substring(iCount,iCount+1),10);
if ( fvalue3 >= 5 )
{
fvalue = parseInt(anumber1[0],10) + 1;
}
else
{
//对于传入的形如111.834999999998 的处理(传入的计算结果就是错误的,应为111.835)
if ( fvalue3 == 4 && anumber[1].length > 10 && parseInt(anumber[1].substring(iCount+1,iCount+2),10) == 9 )
{
fvalue = parseInt(anumber1[0],10) + 1;
}
else
{
fvalue = parseInt(anumber1[0],10);
}
}
}
//如果是负数就用0减四舍五入的绝对值
if ( zs )
{
return fvalue / iB;
}
else
{
return 0 - fvalue / iB;
}
}
调用 round(3.3245,3)//3.325
问题就得到解决了
二、原型上解决
Number.prototype.toFixed = function (n) {
// n为期望保留的位数,超过限定,报错!
if (n > 20 || n < 0) {
throw new RangeError('toFixed() digits argument must be between 0 and 20');
}
// 获取数字
const number = this;
// 如果是NaN,或者数字过大,直接返回'NaN'或者类似'1e+21'的科学计数法字符串
if (isNaN(number) || number >= Math.pow(10, 21)) {
return number.toString();
}
// 默认保留整数
if (typeof (n) == 'undefined' || n == 0) {
return (Math.round(number)).toString();
}
// 先获取字符串
let result = number.toString();
// 获取小数部分
const arr = result.split('.');
// 整数的情况,直接在后面加上对应个数的0即可
if (arr.length < 2) {
result += '.';
for (let i = 0; i < n; i += 1) {
result += '0';
}
return result;
}
// 整数和小数
const integer = arr[0];
const decimal = arr[1];
// 如果已经符合要求位数,直接返回
if (decimal.length == n) {
return result;
}
// 如果小于指定的位数,补上
if (decimal.length < n) {
for (let i = 0; i < n - decimal.length; i += 1) {
result += '0';
}
return result;
}
// 如果到这里还没结束,说明原有小数位多于指定的n位
// 先直接截取对应的位数
result = integer + '.' + decimal.substr(0, n);
// 获取后面的一位
let last = decimal.substr(n, 1);
if (/^\d(9){
5,}[89]$/.test(decimal.substr(n))) {
last += last + 1;
}
// 大于等于5统一进一位
if (parseInt(last, 10) >= 5) {
// 转换倍数,转换为整数后,再进行四舍五入
const x = Math.pow(10, n);
// 进一位后,转化还原为小数
result = (Math.round((parseFloat(result) * x)) + 1) / x;
// 再确认一遍
result = result.toFixed(n);
}
return result;
};
如果对大家有起到帮助,可以点个赞