2013-07-03 13 views
1

이것은 반올림하는 방법에 대한 stackoverflow 답변에서 가져온 반올림 기능입니다. 반올림 최대 2dp (기본값)자바 스크립트 반올림 실패

예 : 2.185 2.19

function myRound(num, places) { 
    if (places== undefined) { 
     // default to 2dp 
     return Math.round(num* 100)/100; 
    } 
    var mult = Math.pow(10,places); 

    return Math.round(num* mult)/mult; 
} 

에 그것은 잘 작동했지만 지금 우리가 발견 한 약간의 오차가 그 안에 (모두 크롬과 IIS 7.5에서와 같은 JScript를 기존의 ASP를 실행)으로 이동한다.

예컨대 :

alert(myRound(2.185));  // = 2.19 
alert (myRound(122.185)); // = 122.19 
alert (myRound(511.185)); // = 511.19 
alert (myRound(522.185)); // = 522.18 FAIL!!!! 
alert (myRound(625.185)); // = 625.18 FAIL!!!! 

는 아는 사람 있나요 :

  1. 을 이런 일이 발생하는 이유.
  2. 이렇게 임의의 반올림 오류없이 최대 2dp로 반올림 할 수있는 방법.

갱신 : OK, 문제의 핵심은 그 JS에서, 625.185 * 100 = 62518.499999 우리가이 이상 어떻게받을 수 있나요?

+0

이것을 사용할 수 있습니다 :'return + (num.toFixed (2));'. 그러나 일반적으로 모든 계산을 먼저 실행하고 인쇄 직전에 결과를 반올림하는 것이 가장 좋습니다. – Teemu

+0

@teemu, 그것은 오류를 일으키는 반올림이고, toFixed는 불행히도 같은 오류가 있습니다. –

+0

여러 가지 숫자로 IE10과 FF21로 이것을 테스트했지만 반올림 오류가 발생하지 않았습니다 ... – Teemu

답변

0

확인을 클릭하면 문제에 대한 "완전한"해결책을 찾았습니다.

첫째, 여기에서 Big.js을 donwnloaded : 그것은 JScript를/ASP를 작동 할 수 있도록

https://github.com/MikeMcl/big.js/ 그런 다음 소스를 수정 : 그런 다음 큰 유형을 사용하여 내 계산을했고, 큰에서는 toFixed을 사용

/* big.js v2.1.0 https://github.com/MikeMcl/big.js/LICENCE */ 
var Big = (function (global) { 
    'use strict'; 
: 
// EXPORT 
return Big; 
})(this); 

(DP)를 선택한 다음 thusly 히 번호로 다시 변환 :

var bigMult = new Big (multiplier); 
var bigLineStake = new Big(lineStake); 
var bigWin = bigLineStake.times(bigMult); 
var strWin = bigWin.toFixed(2); // this does the rounding correctly. 
var win = parseFloat(strWin); // back to a number! 

을이 기본적으로 빅스가 모두 제대로 작동하는 것 같다 자사에서는 toFixed에서 반올림 자신의 사용 사례.

Shame Big에는 문자열을 거치지 않고 번호로 다시 변환하는 방법이 있습니다.

1

값에 toFixed 함수를 사용해보십시오. 예 :

var value = parseFloat(2.185); 
var fixed = value.toFixed(2); 
alert(fixed); 

나는 잘 작동했다.

EDIT : parseFloat (stringVar)를 사용하여 문자열을 숫자로 변환 할 수 있습니다.

EDIT2 :

function myRound(num, places) { 
    return parseFloat(num.toFixed(places)); 
} 

편집 3 :

업데이트 대답, 테스트 작업 :

function myRound(num, places) { 
    if (places== undefined) { 
    places = 2; 
    } 
    var mult = Math.pow(10,places + 1); 
    var mult2 = Math.pow(10,places); 
    return Math.round(num* mult/10)/mult2; 
} 

EDIT 4 :

,

는 의견에서 언급 한 대부분의 예에서 테스트 :

function myRound(num, places) { 
    if (places== undefined) { 
    places = 2; 
    } 
    var mult = Math.pow(10,places); 
    var val = num* mult; 
    var intVal = parseInt(val); 
    var floatVal = parseFloat(val); 

    if (intVal < floatVal) { 
     val += 0.1; 
    } 
    return Math.round(val)/mult; 
} 

편집 5 : I 찾을 관리 유일한 해결책은 정확한 진수에 라운드 얻기 위해 문자열을 사용하는 것입니다. String 프로토 타입 확장 메서드 인 replaceAt를 사용하여 아래에 솔루션이 붙여 넣어집니다. 누군가가 작동하지 않는 예를 발견했는지 확인하고 알려주십시오.

function myRound2(num, places) { 
    var retVal = null; 
    if (places == undefined) { 
     places = 2; 
    } 

    var splits = num.split('.'); 
    if (splits && splits.length <= 2) { 
     var wholePart = splits[0]; 
     var decimalPart = null; 
     if (splits.length > 1) { 
      decimalPart = splits[1]; 
     } 
     if (decimalPart && decimalPart.length > places) { 
      var roundingDigit = parseInt(decimalPart[places]); 
      var previousDigit = parseInt(decimalPart[places - 1]); 
      var increment = (roundingDigit < 5) ? 0 : 1; 
      previousDigit = previousDigit + increment; 
      decimalPart = decimalPart.replaceAt(places - 1, previousDigit + '').substr(0, places); 
     } 
     retVal = parseFloat(wholePart + '.' + decimalPart); 
    } 

    return retVal; 
} 

String.prototype.replaceAt = function (index, character) { 
    return this.substr(0, index) + character + this.substr(index + character.length); 
} 
+0

[toFixed()'] (https://developer.mozilla.org/en-US)를 알려주는 것이 유용 할 수 있습니다./docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed)는 문자열을 반환합니다 ...? – Teemu

+0

예를 들어 무의미했습니다. 요한은 경고의 예를 들어 질문했습니다. 항상 parseFloat (string)을 사용하여 숫자를 가져올 수 있습니다. – EnterSB

+0

불행히도 toFixed는 문자열을 반환하고 계산을 계속하려면 숫자가 필요하며 같은 오류가 발생합니다. 즉, 예를 들어 625.185를 입력하면 불행히도 625.18의 잘못된 결과가 나타납니다. –

3

문제가 쉽게 해결되지 않습니다. 이것은 IEEE double이 정확히 모든 소수를 나타낼 수없는 이진 표현을 사용하기 때문에 발생합니다. 625.185에 가장 가까운 내부 표현은 625.184999999994543031789362430572509765625이며 이는 625.185보다 약간 작으며 올바른 반올림은 아래쪽입니다.


상황에 따라 다음과 떨어져 얻을 수 있습니다 :

Math.round(Math.round(625.185 * 1000)/10)/100 // evaluates to 625.19 

이, 예를 들어,하지만, 엄격하게 정확하지 않습니다 때문에, 라운드, 625.1847 위쪽으로 625.19에을 것입니다. 입력에 소수점 이하 세 자리 이상이 없다는 것을 알고있는 경우에만 사용하십시오.


더 간단한 옵션은 반올림 전에 작은 엡실론을 추가하는 것입니다

Math.round(625.185 * 100 + 1e-6)/100 

를이 여전히 타협, 당신은 생각할 수 625.185에 비해 아주 약간 적은 숫자를 가질 수 있기 때문에, 그러나 아마 첫 번째 솔루션보다 강력합니다. 그러나 음수에 유의하십시오.

+0

.0000001을 추가하려고 생각했지만 유효한 (아직 약간 부정확 함) 옵션으로 유효성을 확인했기 때문에 기쁩니다. –

관련 문제