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. 간략한 요약
당분간 알고 있는 몇 가지 해결책. 이 문제를 해결하기 위한 보다 안정적인 타사 오픈 소스 라이브러리가 있는지는 확실하지 않습니다.