디스 프로그래머 (This Programmer)

[JavaScript/자바스크립트] 숫자를 만, 억, 조, 경 등 만 단위 한글로 찍기 + 자바스크립트 연산의 한계값 본문

HTML/CSS/JS/JavaScript

[JavaScript/자바스크립트] 숫자를 만, 억, 조, 경 등 만 단위 한글로 찍기 + 자바스크립트 연산의 한계값

디스 프로그래머 2019. 1. 5. 00:03

[JavaScript/자바스크립트] 숫자를 만, 억, 조, 경 등 만 단위 한글로 찍기 + 자바스크립트 연산의 한계값

간단한 함수이다. 어떠한 숫자가 주어졌을 때 해당 숫자를 만, 억, 조, 경 등 만 단위 한글로 찍는 자바스크립트 함수이다. 사실 이 함수를 만들기 전에 항상 그래왔듯이 다른 사람들이 만들어놓은 걸 찾아봤지만 만족스러운 것이 없었다. 함수 자체가 30~40줄을 넘어버린다던가 의미를 알 수 없는 부분이 많이 있다던가 혹은 출력이 3억 0305만 0050 이런식으로 중간중간 0에 대한 예외처리가 안돼있다던가... 만족스러운 게 없어서 직접 만들었다. 코드샌드박스에서도 확인할 수 있다. : https://codesandbox.io/s/wopm3v546w


※간단하게 뒤에 '원'만 붙이면 숫자를 한국식 돈 단위로 바꿔주는 함수로 사용할 수도 있다.

function numberToKorean(number){
    var inputNumber  = number < 0 ? false : number;
    var unitWords    = ['', '만', '억', '조', '경'];
    var splitUnit    = 10000;
    var splitCount   = unitWords.length;
    var resultArray  = [];
    var resultString = '';

    for (var i = 0; i < splitCount; i++){
         var unitResult = (inputNumber % Math.pow(splitUnit, i + 1)) / Math.pow(splitUnit, i);
        unitResult = Math.floor(unitResult);
        if (unitResult > 0){
            resultArray[i] = unitResult;
        }
    }

    for (var i = 0; i < resultArray.length; i++){
        if(!resultArray[i]) continue;
        resultString = String(resultArray[i]) + unitWords[i] + resultString;
    }

    return resultString;
}

출력 예는 아래와 같다.

실험해보면 실제 출력과 조금 다른 부분이 있을텐데 출력예제에는 1000단위에 콤마까지 찍는 함수를 추가해줬다. 해당 함수는 이곳을 확인하면 알 수 있다. 콤마까지 찍히는 함수의 예제는 아래와 같다.

function numberFormat(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

function numberToKorean(number){
    var inputNumber  = number < 0 ? false : number;
    var unitWords    = ['', '만', '억', '조', '경'];
    var splitUnit    = 10000;
    var splitCount   = unitWords.length;
    var resultArray  = [];
    var resultString = '';

    for (var i = 0; i < splitCount; i++){
        var unitResult = (inputNumber % Math.pow(splitUnit, i + 1)) / Math.pow(splitUnit, i);
        unitResult = Math.floor(unitResult);
        if (unitResult > 0){
            resultArray[i] = unitResult;
        }
    }

    for (var i = 0; i < resultArray.length; i++){
        if(!resultArray[i]) continue;
        resultString = String(numberFormat(resultArray[i])) + unitWords[i] + resultString;
    }

    return resultString;
}

그리고 나는 항상 함수의 재사용성을 중요하게 생각하기 때문에... 이 함수 또한 영어버전으로 재사용이 가능하다. 위 함수에서 7번라인의 unitWords를 원하는 단위로 바꾸고 8번라인의 spliUnit을 자르고 싶은 단위로 변경하면 된다. 영미권에서 하는 1000단위 자르기 코드 예제는 아래와 같다.

function numberToEng(number){
    var inputNumber  = number < 0 ? false : number;
    var unitWords    = ['', 'thousand', 'million', 'billion'];
    var splitUnit    = 1000;
    var splitCount   = unitWords.length;
    var resultArray  = [];
    var resultString = '';

    for (var i = 0; i < splitCount; i++){
        var unitResult = (inputNumber % Math.pow(splitUnit, i + 1)) / Math.pow(splitUnit, i);
        unitResult = Math.floor(unitResult);
        if (unitResult > 0){
            resultArray[i] = unitResult;
        }
    }
    
    for (var i = 0; i < resultArray.length; i++){
        if(!resultArray[i]) continue;
        resultString = String(resultArray[i]) + unitWords[i] + resultString;
    }

    return resultString;
}

영미권에서는 중간에 만 단위 이상의 숫자가 나올 일이 없으므로 numberFormat함수는 제하여도 괜찮다. 출력예제는 아래와 같다.


직접 실험해볼 수 있는 코드샌드박스.

확인버튼을 누르고 iframe안에 있는 Console창을 확인해보자.





그리고 위 함수와 전혀 상관 없는, 이 함수 만들다가 발견한 자바스크립트 연산 한계값에 대한 이야기


그리고 이 함수를 만들다가 이상한 값을 발견하였다. %(Ampersand)연산, 그러니까 나머지 연산(modulo)에 대한 부분인데 위 코드스니핏에서 10번라인을 보면 되겠다. 자바스크립트(Javascript)는 10경 이상의 단위(10^13)부터는 모듈러연산에서 이상한 값이 발생한다. 값은 아래에서 확인할 수 있다.

console.log(33331809384059355000 % 100000); // returns 55136
console.log(33331809384059355000 % 10000);  // returns 5136
console.log(33331809384059355000 % 100);    // returns 36
console.log(33331809384059355000 * 2);      // returns 66663618768118710000(correct) 
console.log(31809384059355000 % 10000);     // returns 5000

실제 자바스크립트로 찍어봐도 옆에 주석으로 적어놓은 값이 리턴될 것이다. 인터넷에서 자바스크립트를 실행할 수 있는 이곳에서 실험해봐도 다음과 같이 출력될 것이다.



곱하기(*)연산은 정확하게 들어맞는 것으로 보아 오버플로우 같은 문제는 아니었다. 그래서 기타 데이터구조 문제가 아닐까 싶어서 관련 문서를 찾아봤지만 ECMA Script명세서에서는 수의 범위를 32bit(0부터 4,294,967,295, 또는 −2,147,483,648부터 2,147,483,647까지)로 정의하고 있다고는 하는데 사실상 더 큰 수끼리의 연산이 정상적으로 되는 것으로 보아 실제 적용된 메모리값은 더 큰 것으로 보인다. 그래서 더 찾아본 결과는 이렇다.


자바스크립트(Javascript)의 수 범위


자바스크립트에서 숫자를 담당하는 Number 클래스에는 MAX_SAFE_INTEGER라는 값이 있다. 이름에서 직관적으로 알 수 있다시피 연산에 있어서 안전한 정수 최댓값이라는 의미이다. 그 숫자는 어떻게 되느냐, 바로 9007199254740991이다. 그렇게 더 찾아본 바 자바스크립트가 연산할 수 있는 수의 범위를 알게 되었다.

(마크다운 수식 적용 코드를 따로 추가한 상태가 아니라 스크린샷으로 대체한다.)


이 값 이상이 돼버리면 Javascript에서의 연산은 신뢰할 수 없다는 얘기이다. 이것도 모르고 무슨 아무도 모르는 비밀섬의 보물을 발견한 것마냥 ECMA공식홈페이지에 버그리포트를 보내고 비서관 닥터 이반스키씨한테 직접 영어로 메일까지 보내며 나댔던 바로 어제의 내 모습이 눈앞에 아른거려 현기증이 난다. ECMA에서 버그 찾아줬다고 고맙다는 메일을 받는 상상의 나래를 펼쳤었는데 말이다. 아무튼 부끄러운 기억이 하나 생겼지만 이것을 계기로 나댐병을 좀 치료할 수 있을 것 같다.

1 Comments
댓글쓰기 폼