자바 스크립트는 대략 라운딩의 정확도에 손실

I. 배경


경우 최근 dashborad 차트 가까운 N 비트로 소수 둥근 관련된 계산. 결과하지 내가 예상대로 같은 계산 된 검색 JS 후에는 간단한이없는 것 같다 ......

두, JS 및 정밀


1, 정밀 가공

첫째, 두 점차로 :

  • 1, 소수점 정밀도의 개념을 포함 할 것이다
  • 2 진수 (스토리지)가 동작 JS를 포함精度处理

실제로, 우리는 아무 문제없이, 산술 진수. 그러나 JS (프로그래밍 언어)에 그리.

2, 정밀도가 손실됩니다

예를 들어, JS의 구현 :

0.1 + 0.2
0.30000000000000004

0.3 - 0.1
0.19999999999999998

0.1 * 0.1
0.010000000000000002

0.3 / 0.1
2.9999999999999996

알 수있는 바와 같이, JS 계산 결과 소수점, 우리는 기대했던하지. 이것은이다 精度丢失문제.

(1) Q : 정밀도의 손실로 어떤 문제를 이끌 것인가?

답변 :

  • 1 결정 (같다 그래서 ===) 논리 오류. 예를 들어,하자 0.1 + 0.2 === 0.3false
  • 2, 그래서 정확성을 초래할 것으로 예상된다 있다는 소수점 오래 자리 특히 후, 특히 크다. 프론트 - 엔드와 같은 표시하기 위해서는, 특히 추 것이다.
(2) Q : 왜는 정확도가 손실인가?

A :와 컴퓨터 (이진 저장) 내부 부동 소수점 표현되는 관계.

JS 사용  IEEE 754표준 64 비트의 더블 정밀도 부동 소수점 표현이 표준은 1980 년부터 표준 부동 소수점 연산이고, 가장 널리 또한 자바, 파이썬 용도로서 부동 소수점 연산 유닛 채용 많은 언어 많은 CPU 사용 .

정확히 표현 할 수없는 이진 부동 소수점 소수의 대부분을 만들 것이 표준은 (사실, 아무것도 표준 부동 소수점 숫자가 정확히 표현 될 수있다). 일반적으로, 당신은 실제로 컴퓨터에 저장하여 소수점을 입력은 대략 이진 부동 소수점 수를 나타냅니다 .

그러나, (통상적으로 매우 작은) 소정 오차 범위 내에서 처리시의 많은 언어는 정확한 타겟 번호로 보정됩니다 보다는 가까운 부분의 출력에 오차 결과 실제 JS의 존재.

특정 원리를 볼 수 있습니다 - "루안 이풍 부동 소수점 이진 표현을" 여기를 반복하지.

(3) Q : 어떻게 정밀도의 손실을 방지하려면?

방법 A : 계산 된 정수에 절반 방법

예를 들어, 우리는 0.1 + 0.2를 계산하려면, 그 후 추가의 정수로 할 마지막 10 결과를 분할 수 10을 곱한 우선이다.

때문에 정수 정밀도가 손실이되지 않습니다 문제. (게다가 간단하지 정수 정밀도)
사실, 많은 타사 라이브러리는이 원리가 사용됩니다.


방법 2 : 사용 타사 라이브러리

  • Math.js
  • decimal.js
  • big.js
  • bignumber.js

방법 셋 : 사용에서는 toFixed () 함수 (권장)

console.log(parseFloat((0.3 + 0.1).toFixed(1))) // 0.4

참고 : toFixed()최상의 parseFloat()일치의 사용. 에서는 toFixed 때문에 문자열을 반환합니다 .

Q : toFixed()왜 소수 대신 문자열을 반환해야합니까? [키]
A : 유일한 디지털에 대한 자바 스크립트의 데이터 유형, 때문에 number유형 (C 언어 나 데이터베이스와 달리도 나누어 INT는, 플로트, 더블), 그리고 숫자 유형, 선도적 인 0과 소수점 후 무시된다 0으로 설정 (예를 들어, 001 1이고; 1.1000 1.1).

다음에 우리는 소개 계속 toFixed()의 반올림에 대한 특성을.

세, JS 계산 방법


에서 상기 :

  • 정밀 계산
  • 정밀 손실

그것은 가능성이 정밀 변경 (소수점 후, 즉 변화 자리)를 만들 것입니다. 우리가 통일 정밀도를해야하는 경우 사용해야합니다 近似(计算)方法.

1 라운딩

(1) 규정

정의에 의해 대략적인 계산, 특정 규칙에 대한 가장 일반적인 방법이있다 째 세부 사항으로하지 않습니다.

(2) Math.round ()

주어진 수의 값은 가장 가까운 반올림 정수 .

Math.Round(2.4) // 2
Math.Round(2.5) // 3
(3) _ 라운드 () -. lodash

주어진 수의 값은 반올림 반올림 번호 (분별 될 수 있음).

이 방법의 lodash, 당신은 정밀도를 반올림 지정할 수 있습니다, 바로 그러한 두 번째 매개 변수로, 몇 가지 추가 기능을 추가, 기본이) Math.round (호출되는 소스 코드를 읽어 보시기 바랍니다.

const _ = require('lodash');
_.round(1.04, 1) //1
_.round(1.05, 1) //1.1
공정 정말 반올림 (4)? [포커스]

때문에 학교에서 그의 매우 어린 나이의 나는 지금 신중하게 생각까지 아니라 정말 찾기 위해, 공정입니다 부여 된 반올림, 반올림 배운 불공정을 .

부기 때 도움을 Alipay의는 다음 코너에 지원 Alipay의 시스템을 가정, 예를 들어, 당신은 자동으로 관심 매일 청소, 보물의 균형 시나리오를 상상하지만, (이자 규칙에 따라) 계산 진수 값은 비트가 많이있을 수 있습니다 그는 반올림하는 방법을 사용하는 경우 확실히 당신에게 대략적인 계산을 제공합니다 :

const _ = require('lodash');
console.log(_.round(1.01, 1)) //1 (我亏了0.01)
console.log(_.round(1.02, 1)) //1 (我亏了0.02)
console.log(_.round(1.03, 1)) //1 (我亏了0.03)
console.log(_.round(1.04, 1)) //1 (我亏了0.04)
console.log(_.round(1.05, 1)) //1.1 (我赚了了0.05)
console.log(_.round(1.06, 1)) //1.1 (我赚了0.04)
console.log(_.round(1.07, 1)) //1.1 (我赚了0.03)
console.log(_.round(1.08, 1)) //1.1 (我赚了0.02)
console.log(_.round(1.09, 1)) //1.1 (我赚了0.01)

1.01 1.09 9 개 번호의 확률이 일관성이 나타나는 가정하면 첫째, 전체 달러, 2 달러 전체가, 둘째로 간주 될 수 없다. 그런 다음 마지막 Alipay의 확실히 할 것이다 손실 1.1-1.05의 분할이 공정하지 않기 때문에.

또한 그릴 수 있습니다 수직선을 반영하기 위해 :

그렇다면 대략적인 계산이 더 공평합니까? 여기서 당신은 은행원의 반올림을 사용할 수 있습니다.

2, 은행원의 반올림

국제적으로 IS를 받아 银行家舍入(은행의 반올림) 알고리즘을.

그것은 IEEE가 설정 한 기준을 반올림합니다. 따라서 모든 IEEE 호환 언어는이 규칙을 채택해야한다.

(1) 규정

또한로 알려진 은행원의 반올림, 둥근 은행도 촬영합니다 (또한 은행의 반올림 숙박 더블) 방법을.

규칙은 그래서 : 둥근 은행 고려해야 할 다섯 비어에 들어간 후, 놀라운 들어가 다섯 전에, 심지어는해야 반올림 전에 다섯 명 방문, 오 후 빈 패리티입니다 .

패리티가 공정한 확률 분포이기 때문에이 자리를 반올림하면 것은, 라운드 여부를 공정 중 5 때문에 키 ", 홀수, 짝수 후 5 명 방문 비어"는이 후, 판사 전에 패리티에 넘겨 가.

물론, 해당 은행이 알고리즘은 반올림보다 알고리즘을 반올림 말할 수있는 더 과학이다 , 그러나 절대적으로 정확하지 않습니다, 이러한 결과가 발생 통계 데이터를 기반으로하기 때문에 반올림은 잘못된 전제는 그 무작위 분포를 흔들어에 맞춰 이러한 데이터 요구 사항.

(2) 사용

당신이 사용하려는 경우 JS는 현재 기본적으로 지원하지 않습니다

  • 1, 자신을 달성하기 위해
  • 이 같은 NPM 타사 패키지를 사용하여 은행을-라운딩

도 3에서는 toFixed

에서는 toFixed () 은행의 반올림에 맞춰 섹션 규칙.

(1) 네 오프 여섯

와 라인에서

(2) 오 비어 진행 후

와 라인에서

오에도 놀라운 들어갈 다섯 전에 폐기하기 전에 (3) 다섯 명 방문 패리티가 비어 있습니다

섹션 준수

//                           //toFixed结果  //银行家舍入结果
console.log(1.05.toFixed(1)) //1.1(+0.05) 1.0(-0.05)
console.log(1.15.toFixed(1)) //1.1(-0.05) 1.2(+0.05)
console.log(1.25.toFixed(1)) //1.3(+0.05) 1.2(-0.05)
console.log(1.35.toFixed(1)) //1.4(+0.05) 1.4(+0.05)
console.log(1.45.toFixed(1)) //1.4(-0.05) 1.4(-0.05)
console.log(1.55.toFixed(1)) //1.6(+0.05) 1.6(+0.05)
console.log(1.65.toFixed(1)) //1.6(-0.05) 1.6(-0.05)
console.log(1.75.toFixed(1)) //1.8(+0.05) 1.8(+0.05)
console.log(1.85.toFixed(1)) //1.9(+0.05) 1.8(-0.05)
console.log(1.95.toFixed(1)) //1.9(-0.05) 2.0(+0.05)
//                           //总计(+0.1)   //总计(0)

에서는 toFixed 확실히 둥근을 준수하지 볼 수 있습니다뿐만 아니라 은행의 반올림 알고리즘은 다르다. (이 특정 계산 방법, 나는 분명하지 않다 왜, 기록 될)

(4) 다른 근사 함수

  • Math.ceil () : 라운드까지 (둥근)
  • Math.floor () : 둥근 아래로 (둥근)
  • 등등 ......

추천

출처www.cnblogs.com/xjnotxj/p/12639408.html