ProgramingTip

C ++로 통화 값을 저장하는 가장 좋은 방법

bestdevel 2021. 1. 10. 22:57
반응형

C ++로 통화 값을 저장하는 가장 좋은 방법


반올림 오류로 부동 소수점이 통화 값을 저장하는 데 적합하지 않다는 것을 알고 있습니다. C ++로 돈을 표현하는 표준 방법이 있습니까?

부스트 라이브러리를 본 결과 아무것도 없었습니다. Java에서는 BigInteger가 방법 인 것 같지만 C ++에서 동등한 것을 수 없습니다. 나는 내 자신의 돈 수업을 할 수있는 것이 좋습니다.


세금 과이 꽤 빨리 곱할 때 오류가 있고 센트로 저장하지 않습니다. 최소한 두 개의 유효 숫자를 추가로 유지하십시오. $ 12.45는 124,500으로 저장됩니다. 부호있는 32 비트 정수로 유지하면 작업 할 $ 200,000 (양수 또는 음수)가 있습니다. 더 큰 숫자 나. 필요한 경우 부호있는 64 비트 정수가 오랫동안 필요한 모든 공간을 제공 할 것입니다.

이 값을 클래스에 래핑하고, 그 값을 만들고, 산술을 수행하고, 할 형식을 지정하는 데 한곳을 제공하는 것이 도움이 될 수 있습니다. 이 또한 저장되는 통화 (USD, CAD, EURO 등)를 스마트하게 할 수있는 중앙 장소를 제공합니다.


실제 금융 시스템 에서이 문제를 다루었 기 때문에 소수점 이하 6 자리 이상 (USD 가정)을 사용하고 싶을 것입니다. 통화 가치에 대해 이야기하고 있기 때문에 여기에서 벗어나지 않을 것입니다. C ++에 10 진수 유형을 추가하기위한 제안 제안은 아직 거기에 알지 못합니다.

여기서 사용하는 가장 좋은 단어 C ++ 유형은 long double입니다.

센트 이상을 사용하는 것이 저장해야한다는 것입니다. 금융 거래에 정수가 아닌 값이 종종 곱해지면 $ 100.25가 10025 * 0.000123523 (예 : APR)로 변환되어 문제가 발생하기 때문에 문제가 발생합니다. 결국 당신은 부동 소수점 땅에있게 될 수있는 변환은 당신에게 많은 비용을 들이게 될 것입니다.

이제 대부분의 간단한 상황에서는 문제가 발생하지 않습니다. 정확한 예를 들어 보겠습니다.

수천 개의 통화 값이 주어지면 각각에 백분율을 곱한 다음 더하면 소수점 이하 자릿수가 충분하지 않은 숫자에 해당 백분율을 곱한 다른 숫자가됩니다. 이제는 일부 상황에서 작동 할 수있을 때 종종 빨리 몇 푼도 떨어져 나가게 될 것입니다. 내 일반적인 경험에서 소수점 이하 6 자리까지의 등급을 유지하는지 확인합니다 (나머지 매개 변수는 정수 부분에 사용할 수 있는지 확인합니다).

또한 수학을 수행하는 경우 저장하는 유형은 중요하지 않습니다. 수학이 단 공연 영역에서 수행되는 경우 배정 밀도로 저장 여부는 중요하지 않습니다. 귀하의 제품은 가장 말하지 않습니다.


즉, 간단한 덧셈이나 뺄셈 이외의 수학을 수행하지 않고 숫자를 저장하면 괜찮을 것입니다. 그러나 그보다 더 복잡한 것이 문제가 있습니다.


최근의 Intelr Decimal 부동 소수점 수학 라이브러리 를 사용 합니다. 특히 금융 응용 프로그램을위한 이진 부동 소수점 산술 (IEEE 754r)에 대한 몇 가지 새로운 표준을 구현 합니다.


가장 큰 문제는 자체 반올림입니다!

42,50 유로의 19 % = 8,075 유로. 반올림에 대한 독일 규칙으로 인해 이것은 8,08 €입니다. 문제는 (적어도 내 컴퓨터에서는) 8,075를 이중으로 수 많은 것입니다. 디버거의 변수를이 값으로 변경해도 8,0749999가됩니다 ....

그리고 이것은 내 반올림 함수 (및 내가 생각할 수있는 부동 소수점 논리에 대한 다른 모든 것)가 8,07 €를 생성하기 때문에 실패하는 곳입니다. 유효 숫자는 4 값은 내림됩니다. 그리고 그것은 명백한 잘못이며 가능한 한 부동 소수점 값을 사용하지 않습니다.

42,50 €를 Integer 42500000으로 표현하면 잘 작동합니다.

42500000 * 19/100 = 8075000. 이제 8080000 이상의 반올림 규칙을 적용 할 수 있습니다. 표시상의 쉽게 쉽게 통화 값으로 변환 할 수 있습니다. 8,08 유로.

그러나 나는 항상 그것을 수업에서 마무리 할 것입니다.


달러 대신 센트 수에 대한 변수를 유지하는 것이 좋습니다. 반올림 오류를 제거해야합니다. 표준 달러 / 센트 형식으로 표시하는 것은 뷰 문제입니다.


어떤 유형을 결정하든간에 다른 시간에 사용하기 위해 "typedef"를 사용하는 것이 좋습니다.


데이터 범위를 제공합니다.

부동 소수점은 6 ~ 7 자리의 최대에만 약 + -9999.99를 의미합니다. 대부분의 금융 애플리케이션에는 쓸모가 없습니다.

double은 13 자리 숫자에 적합하고 + ​​-99,999,999,999.99, 큰 숫자를 사용할 여전히주의하십시오. 두 책의 많은 부분이 빼면 많은 부분이 제거 사실을 인식하십시오 (잠재적 인 문제는 수치 분석에 관한 참조).

32 비트 정수는 + -20 억에 적합합니다 (페니로 소수점하면 소수점 2 자리까지).

64 비트 정수는 모든 돈을 처리하지만 다시 한 번, 변환 할 때주의하고 앱에서 부동 / 더블 일 수있는 다양한 비율로 곱합니다.

핵심은 문제 영역을 이해하는 것입니다. 어떤 법적 요구 사항이 있습니까? 값을 어떻게 표시 하시겠습니까? 얼마나 자주 전환이 발생합니까? 국제화가 필요합니까? 결정을 내리기 전에 먼저 질문에 답할 수 있는지 확인하십시오.


십진수 데이터 유형을 시도 할 수 있습니다.

https://github.com/vpiotr/decimal_for_cpp

정렬 중심의 가치 (돈 잔고, 환율, 이자율), 사용자 정의를 저장하도록 설계되었습니다. 최대 19 자리.

C ++ 용 헤더 전용 솔루션입니다.


부스트 라이브러리를 보았는데 거기에 아무것도 없었습니다. 그러나 거기에는 multiprecision / cpp_dec_float 가 있습니다.

이 유형의 기수는 10입니다. 결과적으로 base-2 유형과는 미묘하게 다르게 작동 할 수 있습니다.

따라서 이미 부스트를 사용하고 권한 기본 10 숫자와 50 또는 100 자리 가치 (많음)로 통화 및 연산에 유용 할 것입니다.

보다 :

#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_dec_float.hpp>

int main()
{
    float bogus = 1.0 / 3.0;
    boost::multiprecision::cpp_dec_float_50 correct = 1.0 / 3.0;

    std::cout << std::setprecision(16) << std::fixed 
              << "float: " << bogus << std::endl
              << "cpp_dec_float: " << correct << std::endl;

    return 0;
}

다수 :

플로트 : 0.3333333432674408

cpp_dec_float : 0.3333333333333333

* 나는 float (밑수 2)가 나쁘고 소수점 (밑수 10)이 좋다고 말하는 것이 아닙니다. 그들은 단지 다르게 행동합니다 ...

** 나는 그것이 오래된 게시물이고 boost :: multiprecision이 2013 년에 구현되고 있다는 것을 알고 있습니다.


반올림과 관련된 비즈니스 요구 사항에 따라 나열된. 가장 안전한 방법은 필요한 것으로 정수를 저장하고 반올림 적용시기 / 방법을 아는 것입니다.


정수는 항상 센트 (또는 가장 낮은 통화가 프로그래밍하는 곳)로 저장합니다. 문제는 언젠가 부동 소수점으로 무엇을하든간에 계산이 달라지는 상황을 발견 할 수 있다는 것입니다. 부동 소수점에서. 실제 통화 계산이 진행됨에 따라 반올림되므로 마지막 순간에 반올림하는 것은 답이 아닙니다.

작업 순서를 변경하여 문제를 피할 수 없습니다. 적절한 이진 표현이없는 백분율이 있으면 실패합니다. 회계사는 당신이 한 푼도 빼면 놀라게 될 것입니다.


10 진수 기반 통화를 사용하는 경우 long int를 사용하여 통화를 가장 작은 단위로 저장하는 것이 좋습니다 (예 : 미국 화폐는 센트).

매우 중요합니다. 모든 통화 값에 실제로 포함 된 내용에 따라 이름을 지정해야합니다. (예 : account_balance_cents) 이렇게하면 많은 문제를 피할 수 있습니다.

(이 결과가 나오는 또 다른 예는 백분율입니다. 실제로 100을 곱하지 않은 비율이 포함 된 값을 "XXX_percent"로 지정하지 마십시오.)


솔루션은 간단합니다. 필요한 정확도를 이동 된 정수로 저장합니다. 그러나 읽을 때 double float로 변환하여 계산에 반올림 오류가 적습니다. 그런 다음 데이터베이스에 저장할 때 필요한 정수 정확도로 곱하지만 정수로 자르기 전에 자르기 오류를 보상하기 위해 +/- 1/10을 추가하거나 반올림하려면 +/- 51/100을 추가하십시오. 쉬워요.


GMP의 라이브러리는 당신이 돈 처리에 필요한 임의의 크기의 정수 계산에 사용할 수있는 "의 bignum"구현을 가지고있다. mpz_class에 대한 문서를 참조하십시오 (경고 : 이것은 끔찍하게 불완전하지만 전체 범위의 산술 연산자가 제공됩니다) .


한 가지 옵션은 $ 10.01을 1001로 저장하고 값을 표시 할 때 100D로 나누어 모든 계산을 동전 단위로 수행하는 것입니다.

또는 수레를 사용하고 가능한 마지막 순간에만 둥글게하십시오.

종종 작업 순서를 변경하여 문제를 완화 할 수 있습니다.

10 % 할인의 경우 값 * .10 대신 (값 * 10) / 100을 사용하면 큰 도움이됩니다. (.1은 반복 바이너리임을 기억하십시오)


우리 금융 기관은 "더블"을 사용합니다. 우리는 "고정 수입"상점이기 때문에 어쨌든 double을 사용하는 복잡한 알고리즘을 많이 가지고 있습니다. 요령은 최종 사용자 프레젠테이션이 double의 정밀도를 초과하지 않도록하는 것입니다. 예를 들어 총 수조 달러의 거래 목록이있을 때 반올림 문제로 인해 쓰레기를 인쇄하지 않도록해야합니다.


계속해서 돈 ( http://junit.sourceforge.net/doc/testinfected/testing.htm ) 또는 통화 () 클래스 (필요한 것에 따라 다름)를 작성하십시오. 그것을 테스트하십시오.


달러와 센트 금액을 두 개의 개별 정수로 저장합니다.


32 비트에는 signed long을 사용하고 64 비트에는 signed long을 사용합니다. 이렇게하면 기본 수량 자체에 대한 최대 저장 용량이 제공됩니다. 그런 다음 두 개의 맞춤형 조작기를 개발합니다. 환율에 따라 해당 수량을 변환하고 해당 수량을 선택한 통화로 형식화하는 하나. 다양한 재무 운영 및 규칙에 대한 더 많은 조작자를 개발할 수 있습니다.

참조 URL : https://stackoverflow.com/questions/149033/best-way-to-store-currency-values-in-c

반응형