부동 소수점 값의 문제점은 고정 된 양의 비트로 무한한 (연속적인) 값을 나타내려고한다는 것입니다. 따라서 당연히 약간의 손실이 발생해야하며 일부 가치에 물릴 것입니다.
컴퓨터가 1.275를 부동 소수점 값으로 저장하면 실제로 1.275인지 1.27499999999999993인지 또는 1.27500000000000002인지 기억하지 않습니다. 이 값은 소수점 이하 두 자리로 반올림 한 후에 다른 결과를 제공해야하지만 컴퓨터의 경우 부동 소수점 값으로 저장 한 후 정확히 동일 하게 보이 므로 손실 된 데이터를 복원 할 방법이 없기 때문에 그렇지 않습니다 . 추가 계산은 이러한 부정확도 만 누적합니다.
따라서 정밀도가 중요한 경우 처음부터 부동 소수점 값을 피해야합니다. 가장 간단한 옵션은
- 용도 헌신적 인 라이브러리를
- 문자열을 사용하여 값을 저장하고 전달합니다 (문자열 연산과 함께 제공)
- 정수를 사용하십시오 (예 : 실제 값의 100 분의 1 정도를 전달할 수 있습니다 (예 : 달러 대신 금액을 센트로 표시))
예를 들어, 정수를 사용하여 100 분의 1을 저장하는 경우 실제 값을 찾는 기능은 매우 간단합니다.
function descale(num, decimals) {
var hasMinus = num < 0;
var numString = Math.abs(num).toString();
var precedingZeroes = '';
for (var i = numString.length; i <= decimals; i++) {
precedingZeroes += '0';
}
numString = precedingZeroes + numString;
return (hasMinus ? '-' : '')
+ numString.substr(0, numString.length-decimals)
+ '.'
+ numString.substr(numString.length-decimals);
}
alert(descale(127, 2));
문자열을 사용하면 반올림이 필요하지만 여전히 관리 가능합니다.
function precise_round(num, decimals) {
var parts = num.split('.');
var hasMinus = parts.length > 0 && parts[0].length > 0 && parts[0].charAt(0) == '-';
var integralPart = parts.length == 0 ? '0' : (hasMinus ? parts[0].substr(1) : parts[0]);
var decimalPart = parts.length > 1 ? parts[1] : '';
if (decimalPart.length > decimals) {
var roundOffNumber = decimalPart.charAt(decimals);
decimalPart = decimalPart.substr(0, decimals);
if ('56789'.indexOf(roundOffNumber) > -1) {
var numbers = integralPart + decimalPart;
var i = numbers.length;
var trailingZeroes = '';
var justOneAndTrailingZeroes = true;
do {
i--;
var roundedNumber = '1234567890'.charAt(parseInt(numbers.charAt(i)));
if (roundedNumber === '0') {
trailingZeroes += '0';
} else {
numbers = numbers.substr(0, i) + roundedNumber + trailingZeroes;
justOneAndTrailingZeroes = false;
break;
}
} while (i > 0);
if (justOneAndTrailingZeroes) {
numbers = '1' + trailingZeroes;
}
integralPart = numbers.substr(0, numbers.length - decimals);
decimalPart = numbers.substr(numbers.length - decimals);
}
} else {
for (var i = decimalPart.length; i < decimals; i++) {
decimalPart += '0';
}
}
return (hasMinus ? '-' : '') + integralPart + (decimals > 0 ? '.' + decimalPart : '');
}
alert(precise_round('1.275', 2));
alert(precise_round('1.27499999999999993', 2));
가까운이 기능 라운드, 참고 0에서 먼 관계가 , 동안 IEEE 754 , 가까운 반올림하는 것이 좋습니다 도에 관계 부동 소수점 연산뿐만 기본 동작. 이러한 수정은 독자의 연습으로 남습니다. :)