Javascript의 계산 오류 수정에 대한 해결 방법

黄舟
풀어 주다: 2017-08-22 10:40:21
원래의
1938명이 탐색했습니다.

이 글은 주로 Javascript의 toFixed 계산 오류(뱅커의 반올림 방식에 의존하는 결함)에 대한 해결책을 소개합니다. 도움이 필요한 친구들이 참고할 수 있습니다.

서문

회사 프로젝트에는 부동 소수점 가격 계산 모듈이 많이 있어서 다음과 같은 생각이 들었습니다.

컴퓨터 바이너리 환경에서 부동 소수점 숫자의 계산 정밀도가 부족한 문제


console.log(.1+.2);
0.30000000000000004
로그인 후 복사

위의 문제를 해결하기 위해 toFixed 메소드를 사용했지만 오류가 발생했습니다. 소수점 이하 자릿수가 5로 끝나는 반올림 오류 문제


var num = 0.045;
console.log(num.toFixed(2));
0.04
로그인 후 복사

이것을 출발점으로 삼아 일련의 탐구가 시작되었습니다. toFixed, 그리고 마침내 몇 가지 유용한 정보를 찾았습니다. toFixed에서 사용하는 계산 규칙은 다음과 같습니다.

뱅커 반올림: 소위 뱅커 반올림 방법은 본질적으로 반올림 짝수(5반올림이라고도 함)입니다. 짝수) 방식.

간단히 말하면: 5로 반올림하는 것을 고려하세요. 5 이후의 숫자가 0이 아니면 1을 더하고, 5 이후의 숫자가 0이면 홀수 또는 짝수로 보고, 5 이전의 숫자가 짝수이면 5 이전의 숫자가 홀수이면 1로 반올림합니다.

Text

이제 우리는 소위 은행가의 반올림 방법을 검증할 것입니다. 검증은 4, 5, 6을 반올림 비트로 사용하여 고정되었습니다(예: Chrome 사용).

4를 반올림 숫자로 사용:


var num = 0.004;
console.log(num.toFixed(2));
0.00
var num = 0.014;
console.log(num.toFixed(2));
0.01
var num = 0.094;
console.log(num.toFixed(2));
0.09
로그인 후 복사

4의 끝 부분에 있는 이 상황에서 toFixed는 꽤 잘 수행되며 오류 문제도 없습니다.

6을 반올림 숫자로 사용하세요.


var num = 0.006;
console.log(num.toFixed(2));
0.01
var num = 0.016;
console.log(num.toFixed(2));
0.02
var num = 0.096;
console.log(num.toFixed(2));
0.10
로그인 후 복사

은 6으로 끝납니다. 이 경우 toFixed도 잘 수행되며 오류 문제가 없습니다.

반올림 숫자로 5 사용:

5 이후 0이 아닌 경우:



var num = 0.0051;
console.log(num.toFixed(2));
0.01
var num = 0.0052;
console.log(num.toFixed(2));
0.01
var num = 0.0059;
console.log(num.toFixed(2));
0.01
로그인 후 복사

규칙에 따르면 5 이후 0이 아닌 경우 1이 고급이 아닌 것으로 확인되었습니다. 문제.

5를 반올림 숫자로 사용:

5 이후의 숫자는 0: 이번 상황은 좀 특수해서 toFixed 메소드의 계산 오류라서 많이 확인하고 공통으로 검색해봤습니다. 주류 브라우징 기기에서 테스트됨:


다음 테스트 사례를 예로 들어 보겠습니다.



var num = 0.005;
console.log(num.toFixed(2));
var num = 0.015;
console.log(num.toFixed(2));
var num = 0.025;
console.log(num.toFixed(2));
var num = 0.035;
console.log(num.toFixed(2));
var num = 0.045;
console.log(num.toFixed(2));
var num = 0.055;
console.log(num.toFixed(2));
var num = 0.065;
console.log(num.toFixed(2));
var num = 0.075;
console.log(num.toFixed(2));
var num = 0.085;
console.log(num.toFixed(2));
var num = 0.095;
console.log(num.toFixed(2));
로그인 후 복사

Chrome, Firefox, Safari, Opera의 결과는 다음과 같습니다.

0.01

0.01
0.03
0.04
0.04
0.06
0.07
0.07
0.09
0.10

ie11 결과는 다음과 같습니다.


0.01

0.02
0.03
0.04
0.05
0.06
0.07
0.08
0.09
0.10

될 수 있어요 Ie11에서는 정상이고 다른 브라우저에서는 실수로 나타나는 것을 확인했습니다. Banker's Rounding 방법의 규칙을 완전히 따르지는 않지만, 이 규칙을 완전히 따르지 않는 것은 이진수에서 부동 소수점 숫자의 함정 때문이라고 생각합니다.


간단히 말하면 toFixed가 부동 소수점 계산의 정확성 부족 문제를 해결하기 위해 도입된 것인지, 아니면 은행가의 반올림 방식을 사용하는 것인지는 모두 정확성 문제를 해결하기 위한 것이지만 이진법과 분리될 수 없습니다. 부동 소수점 환경이지만 적어도 그는 우리가 해결책을 찾을 수 있도록 문제를 찾는 데 도움을 주었습니다.

Solution

아래에서는 Fixed를 다시 작성하여 메서드를 제공합니다.



 Number.prototype.toFixed = function(length)
    {
      var carry = 0; //存放进位标志
      var num,multiple; //num为原浮点数放大multiple倍后的数,multiple为10的length次方
      var str = this + ''; //将调用该方法的数字转为字符串
      var dot = str.indexOf("."); //找到小数点的位置
      if(str.substr(dot+length+1,1)>=5) carry=1; //找到要进行舍入的数的位置,手动判断是否大于等于5,满足条件进位标志置为1
      multiple = Math.pow(10,length); //设置浮点数要扩大的倍数
      num = Math.floor(this * multiple) + carry; //去掉舍入位后的所有数,然后加上我们的手动进位数
      var result = num/multiple + ''; //将进位后的整数再缩小为原浮点数
      /*
      * 处理进位后无小数
      */
      dot = result.indexOf(".");
      if(dot < 0){
        result += &#39;.&#39;;
        dot = result.indexOf(".");
      }
      /*
      * 处理多次进位
      */
      var len = result.length - (dot+1);
      if(len < length){
        for(var i = 0; i < length - len; i++){
          result += 0;
        }
      }
      return result;
    }
로그인 후 복사
이 메서드의 일반적인 아이디어는 먼저 반올림 비트를 찾아 위치가 다음보다 큰지 확인하는 것입니다. 5와 같거나 5인 조건 수동 캐리를 1비트로 설정한 다음 매개변수 크기를 사용하여 원래 부동 소수점 수를 매개변수 지수배 10배로 증폭한 다음 플로어를 사용하여 반올림 비트를 포함한 모든 숫자를 제거하고 결정합니다. 이전 수동 캐리를 기준으로 캐리 여부를 결정합니다.

위 내용은 Javascript의 계산 오류 수정에 대한 해결 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿