소수 열에 돈 저장-정밀도와 스케일은 무엇입니까?


173

데이터베이스에 돈 값을 저장하기 위해 10 진수 열을 사용하고 있으며 오늘 사용할 정밀도와 스케일이 궁금합니다.

고정 너비의 문자 열이 더 효율적이라고 가정하기 때문에 십진 열에 대해서도 마찬가지라고 생각했습니다. 그렇습니까?

그리고 어떤 정밀도와 스케일을 사용해야합니까? 나는 24/8의 정밀도를 생각하고있었습니다. 그 잔인 함은 충분하지 않습니까?


이것이 내가하기로 결정한 것입니다.

  • 거래 테이블 자체에 전환율 (해당되는 경우)을 플로트로 저장
  • 계정 테이블에 통화 저장
  • 거래 금액은 DECIMAL(19,4)
  • 변환율을 사용한 모든 계산은 내 응용 프로그램에서 처리되므로 반올림 문제를 계속 제어합니다.

전환율에 대한 플로트는 대부분 참조 용이므로 문제가되지 않는다고 생각합니다. 어쨌든 10 진수로 캐스팅 할 것입니다.

소중한 의견을 보내 주셔서 감사합니다.


2
스스로에게 질문하십시오 : 데이터를 십진 형식으로 저장해야합니까? 나는 데이터를 Cents / Pennies-> integers로 저장합니까?
Terence

5
DECIMAL(19, 4) 인기있는 선택입니다 확인 또한 확인 여기에 사용하는 방법을 많은 소수 자릿수를 결정하는 세계 외화 형식, 희망이 도움이됩니다.
shaijut

답변:


181

한 가지 크기의 제품을 찾고 있다면 DECIMAL(19, 4)인기있는 선택 이라고 제안 합니다 (Google이 신속하게 처리합니다). 나는 이것이 구 VBA / 액세스 / 제트 통화 데이터 타입에서 유래 한 것으로 생각합니다. DecimalVB6 / VBA6 / Jet 4.0에서는 '버전 1.0'스타일 (즉, 완전히 구현되지 않음) 만있었습니다.

고정 소수점 10 진수 값 을 저장 하기위한 경험의 규칙은 실제로 반올림을 허용하는 데 필요한 것보다 적어도 하나 이상의 소수점을 저장하는 것입니다. Currency프런트 엔드 의 이전 유형을 DECIMAL(19, 4)백 엔드의 유형으로 매핑하는 이유 중 하나 Currency는 은행원의 성격을 반올림 했기 때문입니다.DECIMAL(p, s) 입니다.

저장소에 여분의 소수점 이하 자릿수를 DECIMAL사용하면 공급 업체의 기본값을 사용하지 않고 사용자 지정 반올림 알고리즘을 구현할 수 있습니다 (그리고 은행가의 반올림은 놀랍습니다. .

그렇습니다 DECIMAL(24, 8). 대부분의 통화는 소수점 이하 네 자리로 인용됩니다. 8 (또는 그 이상)의 진수 규모가 어디 상황을 알고 있다 필요한 있지만 이것은 '정상적인'금액 (소수 자릿수 네 자리)이 비례하여 소수점 이하 자릿수가 그에 따라 감소해야 함을 암시합니다 (또한 고려하십시오) 이러한 상황에서 부동 소수점 유형). 그리고 오늘날 아무도 십진수 정밀도 24를 요구할만큼 많은 돈이 없습니다 :)

그러나 모든 규모에 맞는 접근법이 아닌 일부 연구는 순서대로 진행될 수 있습니다. GAAP, EU 등 적용 가능한 회계 규칙에 대해 설계자 또는 도메인 전문가에게 문의하십시오. 소수의 다섯 자리로 반올림하기위한 명시적인 규칙을 사용하여 일부 EU 내 국가 간 전송을 모호하게 기억하므로 DECIMAL(p, 6)저장에 사용 합니다. 회계사는 일반적으로 소수점 이하 네 자리를 선호하는 것 같습니다.


PS MONEY반올림시 정확성과 심각한 문제가 있으므로 SQL Server의 데이터 유형을 피하십시오 . 이식성 등과 같은 다른 고려 사항도 있습니다. Aaron Bertrand의 블로그를 참조하십시오 .


하드웨어 디자이너가 그것을 인용했기 때문에 마이크로 소프트와 언어 디자이너는 은행가의 반올림을 선택했습니다. 예를 들어 IEEE (Institute of Electrical and Electronics Engineers) 표준에 명시되어 있습니다. 그리고 수학자들이 선호하기 때문에 하드웨어 설계자들이 그것을 선택했습니다. Wikipedia를 참조하십시오 . 역설 : 1906 년 확률과 오류 이론은 이것을 '컴퓨터의 규칙'(계산을 수행하는 인간을 의미하는 "컴퓨터")이라고 불렀습니다.


1
이 답변을 참조 하고 이 페이지 언어 디자이너 은행원의 반올림을 선택하는 이유에 대한 자세한 내용을.
Nick Chammas

1
어느 날 은행의 반올림은 Microsoft에 의한 것이 아닙니다. @NickChammas : 언어 디자이너의 발명도 아니다. 하드웨어 디자이너가 선택했기 때문에 기본적으로 Microsoft와 언어 디자이너가 선택했습니다. 예를 들어, IEEE (Institute of Electrical and Electronics Engineers) 표준에 명시되어 있습니다. 그리고 수학자들이 선호하기 때문에 하드웨어 설계자들이 그것을 선택했습니다. en.wikipedia.org/wiki/Rounding#History 참조 ; 역설 : 1906 년 확률과 오류 이론은 이것을 '컴퓨터의 규칙'(계산을 수행하는 인간을 의미하는 "컴퓨터")이라고 불렀습니다.
Poogog

9
Bitcoin에 무엇을 사용해야합니까?
툴킷

1
@onedaywhen 왜 DECIMAL(19, 4)더 인기가 DECIMAL(19, 2)있습니까? 대부분의 세계 통화는 소수점 이하 두 자리입니다.
cokedude

3
@ zypA13510 : 그래, 내 주장은 10 년 전이야! 나는 :)에서 quids 해요하지만이 세 번째로, 응답에 대한 투표를 제하고 관련 등 변화의 공정한 청크를 차지하고 내 SO 담당자 있도록
onedaywhen

105

우리는 최근 여러 통화로 값을 처리하고 그 사이에서 변환 해야하는 시스템을 구현했으며 어려운 몇 가지 사항을 알아 냈습니다.

돈에 부동 소수점 숫자를 사용하지 마십시오

부동 소수점 산술은 무언가를 망칠 때까지 눈에 띄지 않을 수있는 부정확성을 소개합니다. 모든 값은 정수 또는 고정 소수점 형식으로 저장해야하며, 고정 소수점 형식을 사용하기로 선택한 경우 해당 형식이 후드에서 수행하는 작업을 정확히 이해해야합니다 (예 : 내부적으로 정수 또는 부동 소수점을 사용합니까) 유형).

계산 또는 변환이 필요한 경우 :

  1. 값을 부동 소수점으로 변환
  2. 새로운 가치를 계산
  3. 숫자를 반올림하고 다시 정수로 변환

3 단계에서 부동 소수점 숫자를 다시 정수로 변환 할 때는 캐스트하지 말고 수학 함수를 사용하여 먼저 반올림하십시오. round특별한 경우에는 floor또는 일 수 있지만 이것은 보통 일 것이다 ceil. 차이점을 알고 신중하게 선택하십시오.

값과 함께 숫자 유형을 저장하십시오.

하나의 통화 만 처리하는 경우에는 이것이 중요하지 않을 수 있지만 여러 통화를 처리하는 데 중요했습니다. USD, GBP, JPY, EUR 등과 같은 통화에 3 자 코드를 사용했습니다.

상황에 따라 다음을 저장하는 것이 도움이 될 수도 있습니다.

  • 숫자가 세전 또는 후인지 여부 및 세율
  • 숫자가 변환의 결과인지 여부 및 변환 된 결과

당신이 다루고있는 숫자의 정확도 한계를 아십시오

실제 가치의 경우 가장 작은 통화 단위만큼 정확해야합니다. 이것은 1 센트, 1 페니, 엔, 펜 등의 값이 없다는 것을 의미합니다. 아무 이유없이 그 값보다 높은 정확도로 값을 저장하지 마십시오.

내부적으로 더 작은 값을 처리하도록 선택할 수 있으며,이 경우 다른 통화 값 유형입니다 . 코드가 어느 것을 알고 있고 혼동하지 않도록하십시오. 여기에서도 부동 소수점 값을 사용하지 마십시오.


이러한 규칙을 모두 추가하여 다음 규칙을 결정했습니다. 실행 코드에서 통화는 가장 작은 단위의 정수를 사용하여 저장됩니다.

class Currency {
   String code;       //  eg "USD"
   int value;         //  eg 2500
   boolean converted;
}

class Price {
   Currency grossValue;
   Currency netValue;
   Tax taxRate;
}

데이터베이스에서 값은 다음 형식으로 문자열로 저장됩니다.

USD:2500

그것은 $ 25.00의 가치를 저장합니다. 통화를 처리하는 코드가 데이터베이스 계층 자체 내에있을 필요가 없으므로 모든 값을 먼저 메모리로 변환 할 수 있기 때문에 그렇게 할 수있었습니다. 다른 상황은 의심 할 여지없이 다른 솔루션에 적합합니다.


그리고 내가 일찍 그것을 명확하게 하지 않은 경우, float을 사용하지 마십시오!


1
절대로 말하지 마십시오. 때로는 금액이 비례하여 나중에 다시 합산되어야합니다. 예 : 총 배당금 (상대적으로 적음)을 발행 주식의 수 (상대적으로 적음)로 나누어 주당 순이익을 제공합니다. 때로는 :) 더 나은 라운드 플로트
onedaywhen

23
나는 결코 내 옆에 서 있지 않습니다. 부동 소수점 사양에는 더 많은 계산을 추가 할 수있는 부정확성이 있습니다. 센트 또는 페니보다 작은 값을 저장해야하는 경우 필요한 정확도 수준을 정의하고 준수하십시오. float를 사용하지 마십시오. 진심으로. 나쁜 생각입니다.
Marcus Downing

4
이 답변은 Douglas Crockford가 "Crockford on JavaScript 시리즈"에 요약 한 자바 스크립트 모범 사례와 일치하며 반올림에서 기계 오류를 피하기 위해 PENNIES에서 모든 통화 계산을 수행하는 것이 좋습니다. 따라서 자바 스크립트에서 통화로 작업하는 경우 값을 이런 식으로 저장하는 것이 좋습니다.
paperreduction

1
@onedayw 주당 순액을 계산하면 비례 배분 된 금액을 합산하여 원래 총액과 비교하고 나머지를 처리하기위한 전략 (10 진수 / 정수 유형 사용시)을 고안 할 수 있습니다.
Shiv

2
Mysql의 bigint경우 양을 기준으로 정렬 하려면 정수 (2500)를 a로 저장하는 것이 좋습니다 . 그리고 큰 정수를 다룰 때 PHP 32 비트로 시간을 낭비하지 말고 64 비트 또는 Node.JS로 업그레이드하십시오.)
Ricky Boyce

4

MySQL에서 돈을 처리 할 때 돈 가치의 정밀도를 알고 있으면 DECIMAL (13,2)을 사용하고 충분히 빠른 대략적인 가치를 원한다면 DOUBLE을 사용하십시오. 따라서 응용 프로그램이 최대 1 조 달러 (또는 유로 또는 파운드)의 돈 값을 처리해야하는 경우 다음과 같이 작동합니다.

DECIMAL(13, 2)

또는 GAAP 를 준수해야하는 경우 다음을 사용하십시오.

DECIMAL(13, 4)

3
2500 페이지 문서의 내용 대신 GAAP 가이드 라인 의 특정 부분에 링크 할 수 있습니까 ? 감사.
ReactingToAngularVues

@ReactingToAngularVues 페이지가 변경된 것 같습니다. 죄송합니다
pollux1er

2

소수점 이하 4 자리는 세계에서 가장 작은 통화 하위 단위를 저장하는 정확도를 제공합니다. 소액 결제 (nanopayment ?!) 정확성이 필요한 경우 추가로 이월 할 수 있습니다.

나는 또한 DECIMALDBMS 특정 돈 유형을 선호 합니다. 응용 프로그램 IMO에서 이러한 종류의 논리를 유지하는 것이 더 안전합니다. 같은 줄을 따라 또 다른 방법은 단순히 응용 프로그램 수준에서 수행되는 사람의 가독성 (¤ = 통화 기호)을 위해 ¤unit.subunit으로 서식을 지정하는 [long] 정수를 사용하는 것입니다.


1

SQL Server의 money 데이터 유형은 소수점 이하 4 자리입니다.

SQL Server 2000 온라인 설명서에서 :

통화 데이터는 양 또는 음의 금액을 나타냅니다. Microsoft® SQL Server ™ 2000에서 화폐 데이터는 money 및 smallmoney 데이터 유형을 사용하여 저장됩니다. 화폐 데이터는 소수점 이하 네 자리까지 정확하게 저장할 수 있습니다. money 데이터 유형을 사용하여 -922,337,203,685,477.5808에서 +922,337,203,685,477.5807 (값을 저장하려면 8 바이트 필요) 범위의 값을 저장하십시오. smallmoney 데이터 유형을 사용하여 -214,748.3648에서 214,748.3647 범위의 값을 저장하십시오 (값을 저장하려면 4 바이트 필요). 더 많은 소수 자릿수가 필요한 경우 대신 십진 데이터 유형을 사용하십시오.


1

때때로 당신은 센트 미만으로 가야 할 것이고 매우 큰 악마를 사용하는 국제 통화가 있습니다. 예를 들어 고객에게 거래 당 0.088 센트를 청구 할 수 있습니다. 내 Oracle 데이터베이스에서 열은 NUMBER (20,4)로 정의됩니다


1

DB에서 어떤 종류의 산술 연산을 수행하려는 경우 (청구 요금 등을 곱하는 등) 아마도 사람들이 제안한 것보다 훨씬 더 정밀한 것을 원할 것입니다. 응용 프로그램 코드에서 배정 밀도 부동 소수점 값보다 작은 것을 사용하려고합니다.


그것이 제가 생각한 것이었지만 환율 측면에서 (즉, 짐바 웨 달러를 USD로 변환). 매우 작은 소수에서 반올림을 처리하는 방법을 확인하기 위해 (psql, sqlite)를 사용하는 데이터베이스에 대해 몇 가지 실험을 수행합니다.
Ivan

또한 일부 DBMS / 언어에서 부동 소수점에 정확도 문제가 있습니까?
Ivan

2
float는 모든 언어에서 정확도 문제가 있습니다.
Marcus Downing

요즘 가장 일반적인 권장 사항은 임의의 정밀도 (think BigDecimal) 를 사용 하는 것이지만 오랫동안 배정도였습니다 ( double대신에 생각하십시오 float). 또한 임의의 정밀도는 경우에 따라 성능이 크게 저하됩니다. 테스트는 확실히 올바른 접근법입니다.
행크 게이

0

IBM Informix Dynamic Server를 사용중인 경우 DECIMAL 또는 NUMERIC 유형의 작은 변형 인 MONEY 유형이 있습니다. 항상 고정 소수점 유형입니다 (DECIMAL은 부동 소수점 유형일 수 있음). 1에서 32까지의 스케일과 0에서 32까지의 정밀도를 지정할 수 있습니다 (기본값은 16, 정밀도 2). 따라서 저장해야 할 항목에 따라 DECIMAL (16,2)을 사용할 수 있습니다. 여전히 미국 연방 적자를 유지하기에 충분히 크거나 가장 가까운 센트를 사용하거나 더 작은 범위 또는 소수 자릿수를 사용할 수 있습니다.


0

많은 부분에서 귀하 또는 귀하의 고객의 요구 사항에 따라 사용할 정밀도와 규모가 결정되어야한다고 생각합니다. 예를 들어 GBP로만 돈을 처리하는 전자 상거래 웹 사이트의 경우 Decimal (6, 2)로 유지해야합니다.


0

답변이 늦었지만 사용했습니다.

DECIMAL(13,2)

내가 생각하는 바에 따르면 99,999,999,999.99까지 허용해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.