Résoudre le problème de précision inexacte lors de l'utilisation de toFixed() pour arrondir

Problème : La précision est inexacte lors de l'arrondi à trois décimales, comme num=3,3245, mais le résultat est bien 3,324

Analyse de la raison :
j'ai découvert après avoir vérifié certaines informations sur Internet,
1. Tous les calculs à l'intérieur de JS sont calculés en mode binaire.
2. La longueur de la valeur binaire ne peut pas être stockée dans JS sans limite. (jusqu'à 52 bits)

La couche inférieure de notre ordinateur est 0 et 1. Bien sûr, l'ordinateur ne peut pas conserver des choses de longueur infinie (taille infinie). Connaissant les deux points ci-dessus, il ne devrait pas être difficile de comprendre pourquoi JS a des problèmes lors du calcul de très grandes valeurs, alors pourquoi a-t-il également des problèmes lors du calcul de petits nombres à virgule flottante, car à l'intérieur de JS, les nombres à virgule flottante sont également exprimés dans très, très long binaire.

Solution:

1. Méthode personnalisée

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;
	}
}

call round(3.3245, 3) // 3.325

problème résolu

2. Solution prototype

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;
};

Si cela est utile à tout le monde, vous pouvez lui donner un coup de pouce

おすすめ

転載: blog.csdn.net/tq1711/article/details/109313261