JS-부동소수점 연산 처리에 대한 자세한 설명

高洛峰
풀어 주다: 2016-12-05 09:41:27
원래의
1487명이 탐색했습니다.

1. 문제 설명

최근에 프로젝트를 진행 중인데 JS 부동 소수점 연산에 몇 가지 버그가 있는 것을 발견했습니다. :

0.1+0.2 == 0.30000000000000004
  
0.1 + 0.7 == 0.7999999999999999
  
7*0.8 == 5.6000000000000005
  
5.6/7 == 0.7999999999999999
로그인 후 복사

2. 해결 방법

JS 작업 후 약간의 오류가 발생합니다. .Net이나 Java만큼 정확하지 않습니다. 주된 이유는 JS의 초점입니다. 운영 중이 아닌데 가끔 프로젝트에서 사용해야 할 때가 있을 것 같아요. 생각해 보면 두 가지 해결 방법이 있습니다.

해결 방법 1:

작업 결과가 소수점 이하 2~3자리를 유지합니다. 프런트엔드 인터페이스는 일반적으로 더 적은 수의 작업을 사용합니다. 정확도 요구사항은 그리 높지 않습니다. 그러니 소수점 이하 2자리만 찍으세요.

B. 옵션 2:

소수점 이하 자릿수를 정수 연산으로 변환합니다. 예:

0.1+0.2 =》 (1+2)/10 == 0.3
  
0.1 + 0.7 =》 (1+7)/10 == 0.8
  
7*0.8 == (7*8)/10 == 5.6
  
5.6/7 == (56/7)/10 == 0.1
로그인 후 복사

호출의 편의를 위해 공개를 추출합니다. 예를 들어 아래 JSMath 라이브러리에서 JSMath는 덧셈, 뺄셈, 곱셈, 나눗셈을 다시 작성합니다. 먼저 매개변수를 정수로 변환한 다음 JSMath(매개변수 1) 연산(매개변수 2)

매개변수를 실행합니다. 1과 매개변수 2는 각각 첫 번째 숫자와 두 번째 숫자를 계산한 후 Value 속성을 통해 값을 가져옵니다.

(function() {
  
  var JSMath = function() {
    return this;
  }
  
  JSMath.prototype.from = function(value) {
  
    // 支持JSMath参数传递主要是用于嵌套的调用
    if ((typeof(value) == 'object') && (value.value != undefined)) {
      this.value = value.value;
    } else {
      this.value = value;
    }
    return this;
  }
  
  // 加法
  JSMath.prototype.add = function(value) {
    var thisValueString = this.value.toString();
    var valueString = value.toString();
    var timesCount1 = 0;
    var timesCount2 = 0;
    if (thisValueString.indexOf('.') > 0) {
      timesCount1 = thisValueString.split('.')[1].length;
    }
    if (valueString.indexOf('.') > 0) {
      timesCount2 = valueString.split('.')[1].length;
    }
    var maxtimeCount = timesCount1 > timesCount2 ? timesCount1 : timesCount2;
    this.value = (Math.pow(10, maxtimeCount) * this.value + Math.pow(10, maxtimeCount) * value) / Math.pow(10, maxtimeCount);
    return this;
  }
   
 // 减法
  JSMath.prototype.sub = function(value) {
    var thisValueString = this.value.toString();
    var valueString = value.toString();
    var timesCount1 = 0;
    var timesCount2 = 0;
    if (thisValueString.indexOf('.') > 0) {
      timesCount1 = thisValueString.split('.')[1].length;
    }
    if (valueString.indexOf('.') > 0) {
      timesCount2 = valueString.split('.')[1].length;
    }
    var maxtimeCount = timesCount1 > timesCount2 ? timesCount1 : timesCount2;
    this.value = (Math.pow(10, maxtimeCount) * this.value - Math.pow(10, maxtimeCount) * value) / Math.pow(10, maxtimeCount);
    return this;
  }
  
  // 除法  
  JSMath.prototype.div = function(value) {
    var thisValueString = this.value.toString();
    var valueString = value.toString();
    var timesCount1 = 0;
    var timesCount2 = 0;
    if (thisValueString.indexOf('.') > 0) {
      timesCount1 = thisValueString.split('.')[1].length;
    }
    if (valueString.indexOf('.') > 0) {
      timesCount2 = valueString.split('.')[1].length;
    }
    var maxtimeCount = timesCount1 > timesCount2 ? timesCount1 : timesCount2;
    this.value = ((Math.pow(10, maxtimeCount) * this.value) / (Math.pow(10, maxtimeCount) * value));
    return this;
  }
  
  // 乘法
  JSMath.prototype.times = function(value) {
  
    var thisValueString = this.value.toString();
    var valueString = value.toString();
    var timesCount1 = 0;
    var timesCount2 = 0;
    if (thisValueString.indexOf('.') > 0) {
      timesCount1 = thisValueString.split('.')[1].length;
    }
    if (valueString.indexOf('.') > 0) {
      timesCount2 = valueString.split('.')[1].length;
    }
    var maxtimeCount = timesCount1 > timesCount2 ? timesCount1 : timesCount2;
    this.value = (Math.pow(10, maxtimeCount) * this.value * Math.pow(10, maxtimeCount) * value) / Math.pow(10, maxtimeCount * 2);
    return this;
  }
  
  if (window.JSMath == undefined) {
    window.JSMath = function(value) {
      var result = new JSMath();
      result.from(value);
      return result;
    }
  }
})()
로그인 후 복사

B1. 기본 작업

  0.1+0.2
=> JSMath(0.1).add(0.2).value == 0.3
  
7+0.8
=> JSMath(7).times(0.8).value == 5.6
  
5.6/7
=> JSMath(5.6).div(7).value = 0.8
로그인 후 복사

B2.다중 개체 작업

  0.05 + 0.05 + 0.2
=> JSMath(JSMath(0.05).add(0.05)).add(0.2).value == 0.3
  
(5+0.6)/7
=> JSMath(JSMath(5).add(0.6)).div(7).value == 0.8
로그인 후 복사

3. 간략한 요약

당분간 알고 있는 몇 가지 해결책. 이 문제를 해결하기 위한 보다 안정적인 타사 오픈 소스 라이브러리가 있는지는 확실하지 않습니다.


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