본문 바로가기
IT/xPlatform

xPlatfomr 계산 값이 잘못 됐거나, 컴퓨터 마다 계산식이 다를 때

by heavenLake 2020. 6. 10.
반응형

10.95+1.95  를 계산하면 12.9 가 아닌 12.899999999999999 등으로 값이 이상하게 나오는 현상이 발생했다.

 

또한 컴퓨터마다 다른 결과값이 발생했다.

 

투비소프트에 문의해보니 아래와 같은 답변이 왔다.

 

=====================================================================

 

 

안녕하세요. 투비소프트 고객지원팀입니다.

문의하신 현상은 부동수숫점 오차로 인하여 발생되는 현상입니다.
소수점계산이 계산기와 다르게 나오는 이유는 부동소수점 오차에 의한 현상입니다. 이는 브라우저의 개발자 도구 console 창에 자바스크립트로 테스트를 하여도 동일한 결과가 나오게 됩니다.

- 개요 :
현재 사용되는 거의 모든 CPU에서는 부동소숫점 자료형을 표현하는데에 있어서 메모리에서 차지하는 크기를 제한을 두고 있습니다.
제한의 이유는 상대적으로 작은숫자를 자주 사용하지 않으며, 또한 높은 처리속도와 CPU 설계상 용이함을 위해서 고정크기가 필요하기 때문입니다.
이 제한의 결과로서 특정 소수들이 이진수로 표현할때 무한소수로 나타나면 모두 저장할수 없어 그 표현이 제한되어 오차를 가지는 근사값으로 표현됩니다.
이는 1/3 이 10진수로 0.3333.... 과 같이 10진수로는 모두 표현못하는 것과 같이, 0.1이 2진수로 0001100110011100110011..... 으로 무한반복하기 때문입니다.

- 정밀도/해상도 :
부동소숫점이 가지는 표현의 제약때문에 정밀도 또는 해상도라는 표현으로 그 제한을 나타내게 됩니다.
정밀도가 15자리라 하면 소숫점 이하 15자리까지만 표현을 한다는 의미가 됩니다.

- 부동소수점 연산 :
부동소수점으로 연산으로 할때에는 반드시 정밀도에 대한 처리가 필요합니다.

사칙연산 : 연산 결과는 CPU의 처리결과에 따릅니다. 소수에 따라서 오차가 포함될수 있습니다. 가감시에도 결과가 0에 가까울 경우 정밀도 처리가 필요합니다.

비교연산 : 비교연산시 정밀도를 12자리로 사용하여 처리하고 있습니다. 즉, 두 수를 차감하여 그 결과오차가 12자리 이하일때에는 동일한 값으로 처리됩니다.

- 오차처리 :
오차처리를 위하여 Truncate나 Round를 사용하는 것이 일반적인 프로그래밍 개발툴에서 사용하는 방식입니다. (VB,VC등)
마이플랫폼에서는 Truncate,Rount,NumFormat등에서 정밀도를 제공하여 부동소수점의 오차를 처리하도록 하고 있습니다.
일반적으로 오차처리를 위한 정밀도는 공학용으로 8-12 정도, 회계용으로 4-8 정도를 사용합니다.


아래는 처리 방안 입니다.

부동소수점 처리방식의 현황은 다음과 같습니다.

1. Runtime, Ajax의 차이점 (Runtime 전용처리)
Round 함수의 경우, Runtime은 소수점이하 round를 지원하지만, Ajax는 ECMA표준에 맞추어 소수점이하는
지원하지 않습니다.
Math.round(nNumber[, nFractionDigit]) : Runtime
Math.round(nNumber) : Runtime,Ajax


Runtime의 경우, nFractionDigit의 range에 따라 소수점이하가 처리됩니다.

nFractionDigit > 0 : 주어진 소수점 자릿수에 반올림
nFractionDigit <= 0 : 0자리 소수점 자릿수에 반올림

Ajax의 경우 현재 미지원이지만, 추가로 지원될 예정입니다.


2. JavaScript의 Round 처리방식 (Ajax/Runtime 공용처리)
소수점이하/정수자릿수를 포함한 Round의 부동소수점 오차보정처리방식은 다음과 같은 script를 사용합니다.
function roundDight(n, digits)
{
if (digits >= 0)
{
return parseFloat(n.toFixed(digits));
} else {
digits = Math.pow(10, digits);
var t = Math.round(n * digits); // digits;
return parseFloat(t.toFixed(0));
}
}

nFractionDigit >= 0 : 주어진 소수점 자릿수에 반올림
nFractionDigit < 0 : 정수부 자릿수에 반올림


Runtime이 제공하는것과 동일한 처리는 다음과 같습니다..

function roundDight(n, digits)
{
if (digits > 0)
{
return parseFloat(n.toFixed(digits));
} else {
return parseFloat(n.toFixed(0));
}
}

nFractionDigit > 0 : 주어진 소수점 자릿수에 반올림
nFractionDigit <= 0 : 0자리 소수점 자릿수에 반올림

=========================================================
아래와 같이 사용하시기 바랍니다.

function Button00_onclick(obj:Button, e:ClickEventInfo)
{
    trace(10.95+1.95);
    trace(roundDight(10.95+1.95, 1));
}

function roundDight(n, digits)
{
     if (digits >= 0)
    {
        return parseFloat(n.toFixed(digits));
    }

    else

    {
        digits = Math.pow(10, digits);
        var t = Math.round(n * digits); // digits; 
        return parseFloat(t.toFixed(0));
    }
}

감사합니다.

반응형

댓글