sourcetip

회계 응용 프로그램 달러 금액에 float 또는 decimal을 사용합니까?

fileupload 2023. 6. 17. 09:37
반응형

회계 응용 프로그램 달러 금액에 float 또는 decimal을 사용합니까?

우리는 VB.NET과 SQL Server에서 레거시 회계 시스템을 다시 작성하고 있습니다..NET/SQL 프로그래머로 구성된 새로운 팀을 다시 작성하도록 했습니다.대부분의 시스템은 플로트를 사용하여 달러 금액으로 이미 완료되었습니다.제가 프로그래밍한 레거시 시스템 언어에는 부동소수점이 없었기 때문에 아마 소수점을 사용했을 것입니다.

당신의 추천은 무엇입니까?

달러 금액에 대해 float 또는 decimal 데이터 유형을 선택하십시오.

두 가지 모두에 대한 장단점은 무엇입니까?

우리의 일상 스크럼에서 언급된 한 가지 단점은 소수점 두 자리 이상의 결과를 반환하는 금액을 계산할 때 주의해야 한다는 것이었습니다.소수점 두 자리로 반올림하셔야 할 것 같습니다.

다른 단점은 모든 디스플레이와 인쇄된 양에 소수점 두 자리를 표시하는 형식 지정 문이 있어야 한다는 것입니다.저는 이것이 수행되지 않았고 금액이 정확하지 않은 부분을 몇 번 발견했습니다. (예: 10.2 또는 10.2546)

프로는 디스크에서 10진수가 9바이트(10진수 12,2)를 차지하는 8바이트를 차지하는 플로트 전용 접근 방식입니다.

달러 금액에 대해 Float 또는 Decimal 데이터 유형을 사용해야 합니까?

그 답은 쉽다.절대 뜨지 않습니다.절대로!

플로트는 IEEE 754에 따라 항상 이진법으로 지정되었으며, 새로운 표준 IEEE 754R은 10진수 형식만 정의했습니다.대부분의 분수 이항 부분은 정확한 십진수 표현과 같을 수 없습니다.

는 " 의이진다같음쓸이수있다습니과임"로 쓸 수 .m/2^n(m,n정수), (양數, 임數, 의數)m/(2^n*5^n)바이너리에 프라임이 부족하기 때문에factor 5모든 이진수는 소수로 정확하게 표현될 수 있지만 그 반대는 아닙니다.

0.3 = 3/(2^1 * 5^1) = 0.3

0.3 = [0.25/0.5] [0.25/0.375] [0.25/3.125] [0.2825/3.125]

          1/4         1/8         1/16          1/32

따라서 주어진 십진수보다 높거나 낮은 숫자를 갖게 됩니다.항상.

그게 왜 중요합니까?반올림.

정규 반올림은 0을 의미합니다.4명 추락, 5..9명 부상따라서 결과가 다음 중 하나인지 여부가 중요합니다.0.049999999999또는0.0500000000당신은 그것이 5센트를 의미하는 것을 알 수 있지만, 컴퓨터는 그것을 알지 못하고 회전합니다.0.4999과 아래쪽(으)로0.5000위쪽(오른쪽)에

부동 소수점 계산 결과에 항상 작은 오차항이 포함되어 있다는 점을 고려할 때, 결정은 순전히 운이 좋은 것입니다.이진수로 소수를 반올림하여 짝수로 처리하려면 가망이 없습니다.

납득이 안 돼요?당신은 당신의 계정 시스템에 모든 것이 완벽하게 괜찮다고 주장합니까?자산과 부채가 같습니까?좋아요, 그런 다음 각 항목의 형식화된 숫자를 각각 가져와서 구문 분석하고 독립적인 십진법으로 합계합니다!

형식화된 합계와 비교해 보십시오.이런, 뭔가 잘못된 것 같은데요, 그렇죠?

이 계산을 위해서는 매우 정확하고 충실한 작업이 필요했습니다(Oracle의 FLOAT를 사용함). 그래서 "1페니의 10억분의 1"을 정확하게 기록할 수 있었습니다.

그것은 이 오류에 도움이 되지 않습니다.왜냐하면 모든 사람들은 자동적으로 컴퓨터가 정확하다고 생각하기 때문입니다. 그리고 사실상 아무도 독립적으로 확인하지 않습니다.

이 사진은 다음과 같습니다.

photo1,C.O.

이것은 또 다른 상황입니다: 노샘프턴 출신의 남자는 0달러 0센트를 지불하지 않으면 집이 압류될 것이라는 편지를 받았습니다!

photo2,C.O.

먼저 부동소수점 산술대해 모든 컴퓨터 과학자가 알아야것을 읽어야 합니다.그런 다음 어떤 유형의 고정점/임의 정밀도 숫자 패키지(예: Java BigNum 또는 Python 10진수 모듈)를 사용하는 것을 고려해야 합니다.그렇지 않으면, 당신은 큰 상처를 입을 것입니다.그런 다음 네이티브 SQL 10진수 유형을 사용해도 충분한지 확인합니다.

이제는 거의 구식인 고속 x87 부동 소수점 보조 프로세서를 노출하기 위해 부동 소수점과 이중점이 존재합니다.계산의 정확성에 관심이 있거나 한계를 완전히 보완하지 않은 경우에는 사용하지 마십시오.

추가적인 경고로서 SQL Server와 .NET 프레임워크는 반올림에 다른 기본 알고리즘을 합니다.Math(수학)에서 MidPoint Rounding(중간점 반올림) 파라미터를 확인해야 합니다.Round(). .NET 프레임워크는 기본적으로 은행원 반올림을 사용하고 SQL Server는 대칭 알고리즘 반올림을 사용합니다.여기에서 위키백과 기사를 확인하십시오.

회계사에게 물어보세요!그들은 당신이 플로트를 사용하는 것에 대해 눈살을 찌푸릴 것입니다.David Singer가 말한 처럼 정확성에 관심이 없는 경우에만 float를 사용합니다.돈에 관해서라면 항상 반대하겠지만 말입니다.

회계에서 소프트웨어는 부동액을 허용할 수 없습니다.소수점 네 개와 함께 소수점을 사용합니다.

여기 약간의 배경이 있습니다.

어떤 숫자 시스템도 모든 실수를 정확하게 처리할 수 없습니다.모두 한계가 있으며, 여기에는 표준 IEEE 부동 소수점과 부호 있는 소수점이 모두 포함됩니다.IEEE 부동 소수점은 사용되는 비트당 더 정확하지만 여기서는 중요하지 않습니다.

재무 수치는 관련 규정과 함께 수 세기 동안의 종이와 펜 관행을 기반으로 합니다.그것들은 상당히 정확하지만, 더 중요한 것은, 그것들이 재현 가능하다는 것입니다.다양한 숫자와 비율로 일하는 두 명의 회계사가 동일한 숫자를 생각해 내야 합니다.불일치의 여지는 사기의 여지가 있습니다.

따라서 재무 계산의 경우, 정답은 산술을 잘하는 공인회계사와 같은 답을 주는 것입니다.이것은 IEEE 부동 소수점이 아닌 10진수 산술입니다.

부동 소수점에 예기치 않은 무리수가 있습니다.

예를 들어 1/3을 소수점으로 저장할 수 없습니다. 0.33333333...(등)

부동 소수점은 실제로 이항 값과 2 지수의 거듭제곱으로 저장됩니다.

따라서 1.5는 -1(또는 3/2)에 3 x 2로 저장됩니다.

이러한 기저 2 지수를 사용하면 다음과 같은 홀수 무리수가 생성됩니다.

1.1을 플로트로 변환한 다음 다시 변환하면 결과는 다음과 같습니다. 1.09999999989

이는 1.1의 이진 표현이 실제로는 154811237190861 x 2^-47로 이중으로 처리할 수 있기 때문입니다.

이 문제에 대한 자세한 내용은 제 블로그를 참조하십시오. 그러나 기본적으로 스토리지의 경우 소수점 이하의 데이터를 사용하는 것이 좋습니다.

에는 Microsoft SQL Server가 .money데이터 유형 - 일반적으로 재무 스토리지에 가장 적합합니다.소수점 이하 4자리까지 정확합니다.

계산의 경우 더 많은 문제가 있습니다. 부정확도는 극히 일부이지만 검정력 함수에 넣으면 금방 중요해집니다.

하지만 십진법은 어떤 종류의 수학에도 별로 좋지 않습니다. 예를 들어 십진법에 대한 기본적인 지원은 없습니다.

전체를 센트 단위로 저장하는 64비트 정수를 사용하는 것이 좋습니다.

SQL Server의 소수 유형을 사용합니다.

돈을 사용하거나 떠다니지 마세요.

화폐는 소수점 이하 네 자리를 사용하고 소수점 이하를 사용하는 것보다 빠르지만 반올림과 관련하여 몇 가지 명백한 문제와 명확하지 않은 문제를 겪고 있습니다(이 연결 문제 참조).

돈 때문에 플로트를 사용하는 유일한 이유는 정확한 답에 신경 쓰지 않는 것입니다.

플로트는 정확한 표현이 아니므로 정밀도 문제가 발생할 수 있습니다. 예를 들어 매우 크고 작은 값을 추가할 때입니다.그렇기 때문에 정밀도 문제는 충분히 드물 수 있지만 통화에 대해서는 소수형이 권장됩니다.

명확히 하기 위해, 소수점 12,2 유형은 14자리 숫자를 정확하게 저장하는 반면, 플로트는 내부적으로 이진 표현을 사용하기 때문에 저장하지 않습니다.예를 들어, 0.01은 부동 소수점 번호로 정확하게 표현할 수 없습니다. 실제로 가장 가까운 표현은 0.00999998입니다.

제가 개발하는 데 도움을 준 은행 시스템의 경우, 저는 시스템의 "이자 적립" 부분을 담당했습니다.매일, 제 코드는 그날 잔액에 대해 얼마나 많은 이자가 발생했는지 계산했습니다.

이 계산을 위해서는 극도의 정확성과 충실도가 요구되었습니다(Oracle의 FLOAT를 사용함). 따라서 "1페니의 10억분의 1"이 누적된 것을 기록할 수 있었습니다.

이자를 "자본화"할 때(즉,이자를 당신 계좌로 갚는 것) 금액은 1페니로 반올림되었습니다.계좌 잔액에 대한 데이터 유형은 소수점 이하 두 자리였습니다.(사실 그것은 많은 소수점에서 작동할 수 있는 다중 통화 시스템이었기 때문에 더 복잡했습니다 - 하지만 우리는 항상 그 통화의 "페니"로 반올림했습니다.)네 - 손실과 이익의 "분수"가 있는 곳이지만, 컴퓨터 수치가 실현될 때(지급 또는 지급된 돈) 그것은 항상 실제 화폐 가치였습니다.

이는 회계사, 감사 및 테스터를 만족시켰습니다.

따라서 고객에게 확인하십시오.그들은 당신에게 그들의 은행/회계 규칙과 관행을 알려줄 것입니다.

소수를 사용하는 것보다 훨씬 더 나은 것은 일반적인 오래된 정수(또는 일종의 비긴트)만 사용하는 것입니다.이렇게 하면 항상 최고의 정확도를 얻을 수 있지만 정밀도를 지정할 수 있습니다.를 들어, " 들어숫는자예를는▁number▁for"가 있습니다.100을 의미할 수 있습니다.1.00형식은 다음과 같습니다.

int cents = num % 100;
int dollars = (num - cents) / 100;
printf("%d.%02d", dollars, cents);

더 정확하게 하려면 100을 더 큰 값(예: 10 ^ n)으로 변경할 수 있습니다. 여기서 n은 소수점의 수입니다.

회계 시스템에서 주의해야 할 또 다른 점은 누구도 테이블에 직접 액세스해서는 안 된다는 것입니다.즉, 회계 시스템에 대한 모든 액세스는 저장 프로시저를 통해 이루어져야 합니다.

이는 SQL 주입 공격뿐만 아니라 부정 행위를 방지하기 위한 것입니다.부정 행위를 저지르려는 내부 사용자는 데이터베이스 테이블의 데이터를 직접 변경할 수 없습니다.이것은 시스템에서 중요한 내부 제어입니다.

불만을 품은 직원이 데이터베이스의 백엔드로 이동하여 수표를 작성하기 시작하기를 원하십니까?또는 승인 권한이 없는 경우 승인되지 않은 공급업체에 비용을 승인했다는 사실을 숨기시겠습니까?전체 조직에서 재무 데이터베이스의 데이터, 즉 데이터베이스 관리자(DBA)와 백업에 직접 액세스할 수 있는 사람은 두 명뿐입니다.DBA가 여러 명인 경우 두 명만 이 액세스 권한을 가져야 합니다.

만약 당신의 프로그래머들이 회계 시스템에서 부동소수점을 사용한다면, 그들은 내부 통제에 대한 생각에 완전히 익숙치 않고 프로그래밍 노력에서 그것들을 고려하지 않았을 가능성이 높기 때문에 이것을 언급합니다.

저는 SQL의 money type을 화폐 가치 저장에 사용해 왔습니다.최근에 저는 여러 온라인 결제 시스템을 사용해야 했고 그 중 일부는 화폐 가치를 저장하기 위해 정수를 사용한다는 것을 알게 되었습니다.현재 프로젝트와 새로운 프로젝트에서 정수를 사용하기 시작했으며 이 솔루션에 상당히 만족하고 있습니다.

n은 0 <= n 및 n < 100과 같은 자연수인 100 분수 n/100 중 4개만이 부동 소수점 수로 표현될 수 있습니다.이 C 프로그램의 출력을 살펴봅니다.

#include <stdio.h>

int main()
{
    printf("Mapping 100 numbers between 0 and 1 ");
    printf("to their hexadecimal exponential form (HEF).\n");
    printf("Most of them do not equal their HEFs. That means ");
    printf("that their representations as floats ");
    printf("differ from their actual values.\n");
    double f = 0.01;
    int i;
    for (i = 0; i < 100; i++) {
        printf("%1.2f -> %a\n",f*i,f*i);
    }
    printf("Printing 128 'float-compatible' numbers ");
    printf("together with their HEFs for comparison.\n");
    f = 0x1p-7; // ==0.0071825
    for (i = 0; i < 0x80; i++) {
        printf("%1.7f -> %a\n",f*i,f*i);
    }
    return 0;
}

.NET의 Money 유형과 같은 것을 언제든지 작성할 수 있습니다.

이 기사를 보십시오.CLR의 금전적 유형입니다.그 작가는 제가 보기에 훌륭한 작품을 했습니다.

무슨 일을 하든 반올림 오차는 조심해야 합니다.표시하는 것보다 더 높은 정밀도를 사용하여 계산합니다.

금액 데이터 유형을 사용하여 달러 금액을 저장하는 것을 고려해 보셨습니까?

십진법이 1바이트를 더 차지한다는 단점에 대해서는 신경쓰지 말라고 말씀드리고 싶습니다.100만 줄에서는 1MB만 더 사용할 수 있으며 요즘 스토리지는 매우 저렴합니다.

통화 값에 대해 어떤 형태로든 고정점 표현을 사용할 수 있습니다.은행가의 반올림("짝수 반올림"이라고도 함)도 조사하려고 합니다.일반적인 "반올림" 방법에 존재하는 편향을 방지합니다.

항상 십진수를 사용합니다.플로트는 반올림 문제로 인해 부정확한 값을 제공합니다.

부동 소수점 숫자는 기저의 음수 배수의 합인 숫자만 나타낼 수 있습니다. 물론 이진 부동 소수점의 경우 두 개입니다.

이항 부동 소수점으로 정확하게 표시할 수 있는 소수점은 0, 0.25, 0.5 및 0.75뿐입니다.다른 모든 것은 근사치입니다. 0.3333과 같은 방식으로...는 십진수 산술에서 1/3에 대한 근사치입니다.

부동 소수점은 결과의 규모가 중요한 계산에 적합합니다.소수점 이하의 소수점 이하까지 정확하게 하려고 하는 것은 잘못된 선택입니다.

이것은 부동소수점과 소수점을 사용하는 시기를 설명하는 훌륭한 기사입니다.Float은 대략적인 값을 저장하고 소수점 이하는 정확한 값을 저장합니다.

요약하자면, 돈과 같은 정확한 값은 십진법을 사용해야 하고, 과학적 측정과 같은 대략적인 값은 부동액을 사용해야 합니다.

부동 소수점과 소수점 모두 정밀도를 잃을 수 있다는 것을 보여주는 흥미로운 예가 있습니다.정수가 아닌 숫자를 추가한 후 동일한 숫자 부동 소수점을 빼면 정밀도가 손실되는 반면 소수점은 그렇지 않은 경우:

    DECLARE @Float1 float, @Float2 float, @Float3 float, @Float4 float; 
    SET @Float1 = 54; 
    SET @Float2 = 3.1; 
    SET @Float3 = 0 + @Float1 + @Float2; 
    SELECT @Float3 - @Float1 - @Float2 AS "Should be 0";

Should be 0 
---------------------- 
1.13797860024079E-15

정수가 아닌 값을 곱하고 동일한 숫자로 나누면 소수점 이하의 정밀도가 감소하는 반면 부동 소수점 이하의 정밀도는 감소하지 않습니다.

DECLARE @Fixed1 decimal(8,4), @Fixed2 decimal(8,4), @Fixed3 decimal(8,4); 
SET @Fixed1 = 54; 
SET @Fixed2 = 0.03; 
SET @Fixed3 = 1 * @Fixed1 / @Fixed2; 
SELECT @Fixed3 / @Fixed1 * @Fixed2 AS "Should be 1";

Should be 1 
--------------------------------------- 
0.99999999999999900

당신의 회계사들은 당신의 라운드 방식을 통제하고 싶어할 것입니다.플로트를 사용하면 일반적으로 다음과 같이 계속 반올림할 수 있습니다.FORMAT()원하는 방식이 아닌 type 문(사용)floor/ceiling대신).

통화 데이터 유형이 있습니다(money,smallmoney), float 또는 real 대신 사용해야 합니다.소수점(12,2)을 저장하면 반올림을 제거할 수 있지만 중간 단계에서도 반올림을 제거할 수 있습니다. 이는 실제로 금융 애플리케이션에서 원하는 것이 아닙니다.

언급URL : https://stackoverflow.com/questions/61872/use-float-or-decimal-for-accounting-application-dollar-amount

반응형