모든 통화 (달러, 유로 및 파운드와 다른 통화)에 대해 작동하는 단일 데이터 표현이 있습니까?


12

금액을 통화로 나타내는 데 사용할 라이브러리에 대한 많은 질문을 찾을 수 있습니다. 그리고 통화를 IEEE 754 부동 소수점 숫자로 저장해서는 안되는 오래된 문제에 대해. 그러나 더 이상 아무것도 찾지 못하는 것 같습니다. 실제 사용 통화에 대해 알아야 할 것이 훨씬 더 많습니다. 나는 물리적 사용에서 그것을 표현하기 위해 알아야 할 것에 특히 관심이 있습니다 (예를 들어, 달러를 사용하면 $ 0.01 미만의 정밀도를 가지지 않으므로 정수 센트로 표현할 수 있습니다).

그러나 알고있는 유일한 통화가 인기있는 서양 통화 (예 : 달러, 유로 및 파운드) 인 경우 프로그램의 다양성에 대한 가정을하기는 어렵습니다. 순전히 프로그램적인 관점에서 관련 지식은 무엇입니까? 나는 전환의 주제에 대해 걱정하지 않습니다.

특히, 일부 통화로 값을 저장하고 인쇄하려면 무엇을 알아야합니까?


2
모든 프로그래머가 통화 금액을 조작하는 산업에서 일하는 것은 아닙니다.
whatsisname

4
오 당연하지. 그러나 그것은 거의 모든 것에 대해 말할 수 있습니다. 우리는이 질문이 유용하다고 생각하는 사람들은 통화를 사용하는 사람들이라고 생각할 수 있습니다.
Kat

5
NYC의 은행 및 기타 금융 서비스 회사를 위해 많은 개발 작업을 수행했습니다. 그리고 귀하의 질문에 "닫힌 양식"의 답이 없다는 것을 거의 보증 할 수 있습니다. "나는 얼마나 많은 수학을 알아야합니까?" 예를 들어, 1990 년대에 주가는 8 분에서 256 일에서 10 진수로 올라 갔으며 많은 재 프로그래밍이 필요했습니다. 누가 그런 일이 일어날 지 짐작할 수 있었습니까? 애플리케이션이 지원하는 비즈니스와 비즈니스 요구를 지원하기 위해 데이터 (이 경우 통화)를 가장 잘 나타내는 방법을 이해하면됩니다.
John Forkosh

4
내 0.02 : 가격 은 한 가지입니다. 다른 통화 입니다.
Machado

3
나는 모든 통화에 공통 분모가 있어야한다고 생각했습니다. 그러나 아닐 수도 있습니다. 페니 스털링은 현재 1⁄100 파운드이지만 1⁄240 파운드였습니다. 따라서 1/240의 부서뿐만 아니라 전환 날짜가 있으며 이전 펜스의 환율이 아직 전환되지 않았습니다. en.wikipedia.org/wiki/Penny_sterling Cowry shells조차 시작하지 마십시오! en.wikipedia.org/wiki/Shell_money 또는 돈이 현실이 되려면 믿음이 필요하다는 사실 : en.wikipedia.org/wiki/Money StackExchange에 잘 맞지 않더라도 훌륭한 질문입니다!
GlenPeterson

답변:


24

예를 들어, 달러를 사용하면 $ 0.01 미만의 정밀도를 갖지 못합니다

아 진짜? 여기에 이미지 설명을 입력하십시오

IEEE 754 부동 소수점 숫자로 통화를 저장해서는 안되는 오래된 문제.

여기에 이미지 설명을 입력하십시오

인치를 IEEE 754 부동 소수점 숫자로 자유롭게 저장하십시오 . 그들은 당신이 기대하는 방식을 정확하게 저장합니다.

눈금자를 1 인치 단위로 나누는 눈금을 사용하여 저장할 수있는 금액을 IEEE 754 부동 소수점 숫자로 자유롭게 저장하십시오 .

왜? IEEE 754 를 사용할 때 저장하는 방식입니다.

인치에 관한 것은 반으로 나뉘어져 있다는 것입니다. 대부분의 종류의 통화는 10 분의 1로 나뉩니다 (일부 종류는 아니지만 초점을 유지합시다).

이 차이는 대부분의 프로그래밍 언어의 경우 IEEE 754 부동 소수점 숫자의 입력 및 출력 이 10 진수로 표현 된다는 점을 제외하고는 혼란스럽지 않습니다 ! 십진수로 저장되지 않기 때문에 매우 이상합니다.

이 때문에 컴퓨터에 저장을 요청할 때 비트가 어떻게 이상한 일을하는지 알 수 없습니다 0.1. 수학을 할 때 이상한 점만 보이고 이상한 오류가 있습니다.

에서 조쉬 블로흐의 효과적인 자바 :

System.out.println(1.03 - .42);

생산 0.6100000000000001

이것에 대해 가장 잘 말하는 1것은 오른쪽에 앉아있는 것이 아닙니다 . 그것을 얻기 위해 사용해야했던 이상한 숫자입니다. 가장 인기있는 예를 사용하기보다는 0.1문제를 보여주고 문제를 숨기는 반올림을 피하는 예를 사용해야합니다.

예를 들어 왜 이것이 작동합니까?

System.out.println(.01 - .02);

생산 -0.01

우리가 운이 좋았 기 때문에.

나는 때때로 "운"을 얻기 때문에 진단하기 어려운 문제가 싫어.

IEEE 754는 단순히 0.1을 정확하게 저장할 수 없습니다. 그러나 0.1을 저장하고 인쇄하도록 요청하면 0.1이 표시되고 모든 것이 잘된다고 생각합니다. 괜찮지는 않지만 0.1로 돌아 가기 위해 반올림하기 때문에 볼 수 없습니다.

어떤 사람들은 이러한 불일치 반올림 오류를 불러서 다른 사람들과 혼동을 일으 킵니다. 아니요, 반올림 오류가 아닙니다. 반올림은 예정된 작업을 수행하고 소수가 아닌 것을 소수점으로 바꾸어 화면에 인쇄 할 수 있습니다.

그러나 이것은 숫자 표시 방법과 저장 방법 사이의 불일치를 숨 깁니다. 반올림이 발생했을 때 오류가 발생하지 않았습니다. 정확하게 저장할 수없는 시스템에 숫자를 입력하기로 결정하고 그렇지 않은 경우 정확하게 저장되었다고 가정했을 때 발생했습니다.

아무도 π가 계산기에 정확하게 저장 될 것으로 기대하지 않으며 제대로 작동 할 수 있습니다. 따라서 문제는 정밀도조차도 아닙니다. 예상 정밀도에 관한 것입니다. 컴퓨터는 0.1계산기와 마찬가지로 10 분의 1을 표시 하므로 계산기와 10 분의 1을 완벽하게 저장해야합니다. 그들은하지 않습니다. 컴퓨터가 더 비싸기 때문에 놀랍습니다.

불일치를 보여 드리겠습니다.

여기에 이미지 설명을 입력하십시오

1/2과 0.5가 완벽하게 정렬됩니다. 그러나 0.1은 정렬되지 않습니다. 2를 계속 나누면 더 가까이 다가 갈 수 있지만 정확하게 맞지는 않을 것입니다. 우리는 2로 나눌 때마다 점점 더 많은 비트가 필요합니다. 따라서 2로 나누는 모든 시스템에서 0.1을 나타내려면 무한한 수의 비트가 필요합니다. 내 하드 드라이브는 그렇게 크지 않습니다.

따라서 IEEE 754 는 비트가 부족할 때 시도를 중지합니다. 가족 사진을 보관할 하드 디스크 공간이 필요해서 좋네요. 아니야 가족 사진. :피

어쨌든, 당신이 입력 한 것과 당신이 보는 것은 소수점 (오른쪽)이지만 당신이 저장하는 것은 이진수 (왼쪽)입니다. 때로는 그것들이 완전히 동일합니다. 때로는 그렇지 않습니다. 때로는 단순히 그렇지 않을 때도 같은 것처럼 보입니다. 반올림입니다.

특히, 일부 통화로 값을 저장하고 인쇄하려면 무엇을 알아야합니까?

10 진수 기반의 돈을 처리하는 경우 float 또는 double을 사용하지 마십시오.

10 분의 1 페니와 같은 일이 관여하지 않을 것이라고 확신한다면 페니를 보관하십시오. 그렇지 않으면이 통화의 가장 작은 단위가 무엇인지 알아 내고 사용하십시오. 할 수 없다면 BigDecimal 과 같은 것을 사용하십시오 .

내 순 가치는 아마도 64 비트 정수에 항상 적합하지만 BigInteger 와 같은 것은 그보다 큰 프로젝트에서 잘 작동합니다. 그들은 기본 유형보다 느립니다.

그것을 저장하는 방법을 알아내는 것은 문제의 절반에 불과합니다. 또한 표시 할 수 있어야합니다. 좋은 디자인은이 두 가지를 분리합니다. 여기서 float를 사용할 때의 실제 문제는 두 가지가 함께 숨겨져 있다는 것입니다.

여기에 이미지 설명을 입력하십시오


6
IEEE 754가 돈을 위해 작동하지 않는 이유에 대한 또 다른 설명을 실제로 찾지 않았습니다. 나는 OP에서 이것이 다른 곳에서 잘 설명되었다고 언급했다. 마찬가지로 "물리적 사용법"이라는 용어를 사용한 이유가 있습니다. 즉, 가스 가격, 증권 거래소 가치 등은 임의의 정밀도를 가질 수 있지만 실제 돈 (및 수많은 사용자 거래)은 수백 곳을 넘지 않습니다 (그리고 다양한 소프트웨어가 지불 할 수있는 것만 나타내기를 원합니다) 물리적 돈). 내가 궁금했던 한 가지 정보는 통화가 존재하여 더 소수점 자리로 들어가는 것입니다.
Kat

3
부동 소수점의 "이상성"은 반감 대 1/10에 국한되지 않습니다. 이름의 "부동 소수점"측면도 때때로 예기치 않은 결과를 초래합니다.
whatsisname

6
소수화하기 전에 영국 통화는 파운드, 실링 및 펜스 (£ sd)였으며 파운드는 £ 1 == 20s, 1s = 12d이므로 £ 1 = 240d이므로 1d = 0.0046666666666입니다. 따라서 소수로 표시 할 수도 없습니다. 유로화에 합류하기 전에 이탈리아 리라는 2346.4 (2001 년)를 US $로 상회하여 급여 및 주택 가격과 같은 것들이 때때로 단 정밀도 수레의 상한에 도달하고 경제 수치가 두 배의 상한에 도달했습니다.
Steve Barnes

2
나는 통화가 한 가지이고 가격은 또 다른 것이라고 주장하고 지적했다. 가격에 $ 0.01 이상의 정밀도를 가질 수 있지만 그 정밀도로 효과적으로 지불 할 수는 없습니다.
Machado

1
또한 가족 사진 . 피트 :)
Machado

10

금액을 통화로 나타내는 데 사용할 라이브러리에 대한 많은 질문을 찾을 수 있습니다.

내가 설명하는 것처럼 특정 데이터 유형에서 언어의 표준 라이브러리가 부족하지 않으면 "라이브러리"가 필요하지 않습니다.

실제 사용 통화에 대해 알아야 할 것이 훨씬 더 많습니다. 나는 물리적 사용에서 그것을 나타 내기 위해 알아야 할 것에 특히 관심이 있습니다 (예를 들어, 달러로, 당신은 $ 0.01 이하의 정밀도를 가지지 않으므로 정수 센트로 표현할 수 있습니다).

간단히 말해서 부동 소수점 10 진수가 아닌 고정 소수점 10 진수 가 필요합니다 . 예를 들어 Java의 BigDecimal 클래스를 사용하여 통화 금액을 저장할 수 있습니다. 다른 현대 언어에는 C #Python을 포함하여 비슷한 유형이 내장되어 있습니다. 구현은 다양하지만 일반적으로 숫자를 정수로 저장하고 소수 위치는 별도의 데이터 멤버로 사용합니다. 이는 IEEE 부동 소수점 숫자로 홀수 나머지 (예 : 0.0000001)를 제공하는 산술을 수행 할 때도 정확한 정밀도를 제공합니다.

특히, 일부 통화로 값을 저장하고 인쇄하려면 무엇을 알아야합니까?

몇 가지 중요한 사항이 있습니다.

  1. 부동 소수점 대신 실제 10 진수 유형을 사용하십시오.

  2. 통화 금액에는 값 (5.63)과 통화 코드 또는 유형 (USD, CAD, GBP, EUR 등)의 두 가지 구성 요소가 있습니다. 때로는 통화 코드를 무시할 수 있으며 다른 경우에는 통화 코드가 중요합니다. 여러 통화를 허용하는 금융 또는 소매 / 전자 상거래 시스템에서 작업하는 경우 어떻게됩니까? CAD로 고객으로부터 돈을 받으려고하는데 MXN으로 지불하고 싶은 경우 어떻게됩니까? 이러한 값을 혼합 할 수 있으려면 통화 코드와 통화 금액이 포함 된 "돈"유형이 필요합니다 (환율도 있지만 접선을 너무 많이하고 싶지는 않습니다). 동시에, 개인 금융 소프트웨어는 모든 것이 USD 단위이므로 통화 에 대해 걱정할 필요가 없습니다 ( 통화 혼합 할 수는 있지만 필 요는 없습니다).

  3. 통화는 실제로 가장 작은 물리적 단위를 가질 수 있지만 (CAD와 USD에는 센트가 있고 JPY는 단지 ... 엔입니다) 더 작아 질 수 있습니다. CandiedOrange의 답변에 따르면 연료 가격은 10 분의 1 센트입니다. 내 재산세는 달러당 밀 또는 10 분의 1 센트 (USD 달러의 1/1000)로 평가됩니다. 자신을 $ 0.01로 제한하지 마십시오. 이러한 값을 대부분 표시 할 수 있지만 유형은 더 작아야합니다 (위의 10 진수 유형).

  4. 중간 계산은 확실히 1 센트보다 더 정밀해야합니다. 내부 가치가 내부적으로 $ 0.00000001로 반올림 된 소매 / 전자 상거래 시스템에서 일했습니다. 무한 정밀도는 일반적으로 10 진수 유형 (또는 SQL)에서 지원되지 않으므로 약간의 제한 이 있어야합니다 . 예를 들어 Java BigDecimal을 1/3로 나누면 값을 정확하게 표현할 수 없으므로 RoundingMode 또는 MathContext를 지정하지 않고 예외가 발생합니다.

    어쨌든 이것은 특정 경우에 중요합니다. 장바구니에 6 개의 품목이있는 사용자가 있다고 가정하고 체크 아웃합니다. 시스템은 세금을 계산해야하며 품목마다 다르게 세금이 부과 될 수 있으므로 품목별로 계산해야합니다. 각 품목에서 세금을 반올림하면 거래 / 장바구니 수준에서 페니 반올림 오류가 발생할 수 있습니다. 이 문제를 해결하는 한 가지 방법은 세금을 품목 당 더 많은 소수점 이하 자리에 저장하고, 전체 거래에 대한 총액을 얻은 다음, 각 품목을 돌아가서 반올림하여 총 세금이 정확하도록하는 것입니다 (한 품목은 반올림하거나 다른 품목은 내림).

이 모든 것에서 깨달아야 할 중요한 점은 둥근 동전처럼 중요한 것이 올바른 사람들에게 매우 중요 할 수 있다는 것 입니다. 그러나 이들은 모두 해결 된 문제입니다. 위의 사항을 명심하고 스스로 실험을 해보면 실천을 통해 배우게됩니다.


2에, 나는 환율이 적어도 자신의 숫자를 얻는 것으로 충분하다고 생각합니다. 처리 속도는 시간이 지남에 따라 변한다는 점을 고려해야합니다.
이즈 카타

2
+1. 또한 시간이 지남에 따라 통화가 변경됩니다. 브라질에서 우리는 80 년대와 90 년대에 걸쳐 통화 변화를 반복하여 0을 줄이고, 통제 불능 인플레이션으로 인해 필요할 때 통화 이름을 변경했습니다. 이는 통화의 모든 측면이 시간이 지남에 따라 변경 될 수 있음을 의미합니다.
Machado

@Izkata는 분명히 통화를 변경하는 시스템에서 일했습니다. 주제와 관련된 주제를 다루고 싶었습니다. 그러나 이것은 질문의 초점이 아니며 통화 교환 주제에 관한 한 다른 대답을 입력 할 수 있습니다.

'내가 설명하는 것처럼 특정 데이터 유형에서 언어의 표준 라이브러리가 부족하지 않으면 "라이브러리"가 필요하지 않습니다.' 통화는 반, 4 분의 1, 10 분의 1, 8 분의 1 등을 가질 수 있습니다. 즉, 최소한 10 진수로 표현해야합니다. 그러나 우리는 1/3의 통화로 된 통화가 없다는 것을 완전히 확신합니까?
Daniel McLaury

4

많은 개발자가 모든 통화에 대해 단일 데이터 표현에 직면하는 한 곳은 iOS 응용 프로그램의 인앱 구매입니다. 고객은 전 세계 거의 모든 국가의 매장에 연결할 수 있습니다. 그런 상황에서 배정도 숫자 와 통화 코드 로 구성된 구매 가격이 제공됩니다 .

숫자가 클 수 있음을 알고 있어야합니다. 10 달러에 해당하는 통화가 100,000 개가 넘는 통화가 있습니다. 그리고 현재 짐바브웨 달러와 같은 통화가 없어서 100 조 달러 지폐가있을 수 있습니다.

통화를 표시하려면 라이브러리가 필요합니다. 직접 읽을 수있는 기회는 없습니다. 표시는 통화 코드와 사용자 로캘의 두 가지에 따라 다릅니다. 미국 로케일과 캐나다 로케일로 미국 달러와 캐나다 달러가 어떻게 표시 될지 생각해보십시오. 미국에서는 $ 대 CAN $, 캐나다에서는 US $ 대 $가 있습니다. 그것이 OS에 내장되어 있거나 좋은 라이브러리가 있기를 바랍니다.

계산의 경우 모든 계산은 반올림 단계로 끝납니다. 라운딩을 합법적으로 수행하는 방법을 찾아야합니다 . 그것은 프로그래밍 문제가 아니라 법적인 문제입니다. 예를 들어 영국에서 부가가치세를 계산하는 경우 품목별 또는 품목 라인 당 세금을 계산하여 페니로 반올림해야합니다. 반올림하는 것은 통화에 따라 다릅니다. 그러나 규칙은 분명히 국가에 달려 있습니다. 영국에서는 법적으로 정확한 계산이 일본에서는 법적으로 정확하고 그 반대도 마찬가지라고 기대할 수 없습니다.


0

특히, 일부 통화로 값을 저장하고 인쇄하려면 무엇을 알아야합니까?

  • "값 저장" : 고정 소수점 숫자 데이터 유형 및 통화 유형. 나는 이것들이 꽤 분명하다고 생각합니다. 고정 소수점 숫자로 저장하면 반올림이 수반되고 값이 변경 될 수 있습니다. 통화 계산은 다른 문제입니다.
  • "출력하려면" : 사용자 로캘. 운이 좋으면 통화 라이브러리, 천 단위 구분 기호, 소수점 구분 기호, 정밀도 등 모든 작업을 수행 할 수있는 표준 라이브러리가 제공됩니다.

로케일과 관련된 몇 가지 예제 문제 :

  • 미국 로케일의 100 USD는 $ 100.00이고 소수점이 분리 된 점이 US $ 100.00 인 다른 로케일입니다.
  • 일부 국가에서는 숫자를 그룹화하기 위해 천 단위 대신 무수한 방식을 사용합니다 (예 : 10,000.00 대신 1,0000.00).
  • 실질적인 이유로, 사람들은 소액 통화로 모든 숫자를 인쇄하지는 않습니다. 예를 들어 $ 1,000,000,000.00 대신 10 억 달러를 인쇄하기를 원합니다.

또 다른 잠재적 인 문제는 고정 소수점 숫자로 통화를 올바르게 저장하더라도 인쇄에 사용 된 라이브러리가 부동 소수점 만 지원하기 때문에 부동 소수점 숫자로 변환해야 할 수도 있습니다.

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