it-swarm-ko.tech

회계 응용 프로그램 달러 금액에 부동 소수점 또는 소수를 사용합니까?

VB.NET 및 SQL Server에서 기존 회계 시스템을 다시 작성하고 있습니다. 재 작성을 위해 새로운 .NET/SQL 프로그래머 팀을 확보했습니다. 대부분의 시스템은 Floats를 사용하여 달러 금액으로 이미 완료되었습니다. 내가 프로그래밍 한 레거시 시스템 언어에는 Float가 없었으므로 아마도 Decimal을 사용했을 것입니다.

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

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

어느 쪽의 장단점이 있습니까?

우리의 일일 스크럼에 언급 된 한 가지 단점은 소수점 이하 두 자리 이상의 결과를 반환하는 양을 계산할 때주의해야한다는 것입니다. 양을 소수점 이하 두 자리로 반올림 해야하는 것처럼 들립니다.

또 다른 단점은 모든 디스플레이이며 인쇄 된 금액에는 소수점 이하 두 자리를 표시하는 형식 명세서가 있어야합니다. 나는 이것이 이루어지지 않았고 금액이 정확하지 않은 몇 번을 알았습니다. (예 : 10.2 또는 10.2546)

프로는 Float이 디스크에서 8 바이트 만 차지하고 소수는 9 바이트를 차지합니다 (소수 12,2)

76
Gerhard Weiss

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

대답은 쉽습니다. 수레가 없습니다. NEVER !

플로트는 IEEE 754 항상 이진이며, 새로운 표준 IEEE 754R 정의 된 10 진수 형식 만 따릅니다. 소수 이진 부분 중 많은 부분이 정확한 10 진수 표현과 같을 수 없습니다.
모든 이진수는 m/2^n (m, n 양의 정수)로, 소수는 m/(2^n*5^n)로 쓸 수 있습니다.
바이너리에는 소수 factor 5가 없으므로 모든 이진수는 정확히 10 진수로 표현할 수 있지만 그 반대의 경우도 마찬가지입니다.

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 위로를 의미합니다. 따라서 does 결과가 0.049999999999 .... 또는 0.0500000000인지 중요합니다. 5 센트를 의미 할 수도 있지만 컴퓨터가이를 알지 못하고 0.4999 ... 아래로 내림 (잘못된) 및 0.5000 ... 위로 (오른쪽) 반올림합니다.
부동 소수점 계산 결과에 항상 작은 오류 항이 포함되어 있으면 결정이 순조 로울 것입니다. 이진수로 10 진수에서 10 진수로 처리하려는 경우 희망이 없습니다.

확신이 없습니까? 당신은 당신의 계정 시스템에서 모든 것이 완벽하다고 주장합니다.
자산과 부채가 동일합니까? 좋아, 그런 다음 각 항목의 지정된 형식 번호를 가져 와서 구문 분석하고 독립적 인 십진수 시스템으로 합산하십시오! 형식화 된 합계와 비교하십시오.
죄송합니다. 문제가 있습니까?

이 계산에는 극도로 정확한 정확성과 충실도가 필요했습니다 (Oracle의 FLOAT를 사용했습니다).

이 오류에 도움이되지 않습니다. 모든 사람들이 자동으로 컴퓨터가 합산한다고 가정하기 때문에 실제로는 아무도 독립적으로 검사하지 않습니다.

108
TSK
42
Nakilon

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

플로트/더블이 존재하여 현재는 거의 쓸모없는 빠른 x87fp를 노출합니다. 계산의 정확성에 관심이 있거나 제한 사항을 완전히 보상하지 않으면 사용하지 마십시오.

22
Rich Schuler

추가 경고와 마찬가지로 SQL Server와 .Net 프레임 워크는 반올림에 다른 기본 알고리즘을 사용합니다. Math.Round ()에서 MidPointRounding 매개 변수를 확인하십시오. .Net 프레임 워크는 기본적으로 은행가 알고리즘을 사용하고 SQL Server는 대칭 알고리즘 반올림을 사용합니다. Wikipedia 기사를 확인하십시오 here

10
Darrel Miller

회계사에게 문의하십시오! 플로트를 사용하면 눈살을 찌푸리게됩니다. 이전에 게시 된 것과 마찬가지로 정확성에 신경 쓰지 않으면 float 만 사용하십시오. 돈에 관해서는 항상 반대합니다.

회계 소프트웨어에서는 플로트를 사용할 수 없습니다. 소수점 4 자리와 함께 소수점을 사용하십시오.

7
Ricardo C

부동 소수점에 예기치 않은 비합리적인 숫자가 있습니다.

예를 들어 1/3을 10 진수로 저장할 수 없으면 0.3333333333 ...입니다.

실수는 실제로 이진 값과 2 지수의 거듭 제곱으로 저장됩니다.

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

이러한 기수 -2 지수를 사용하면 예를 들어 다음과 같이 이상한 비합리적인 숫자가 생성됩니다.

1.1을 부동 소수점으로 변환 한 다음 다시 변환하면 결과는 다음과 같습니다. 1.0999999999989

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

my blog 에서이 문제에 대한 자세한 내용은 기본적으로 저장의 경우 소수점 이하 자릿수를 사용하는 것이 좋습니다.

Microsoft SQL 서버에는 money 데이터 유형이 있습니다. 이는 일반적으로 금융 스토리지에 가장 적합합니다. 소수점 이하 4 자리까지 정확합니다.

계산의 경우 더 많은 문제가 있습니다. 부정확성은 작은 부분이지만 전력 함수에 넣으면 빠르게 중요해집니다.

그러나 소수는 모든 종류의 수학에 적합하지 않습니다. 예를 들어 소수에 대한 기본 지원은 없습니다.

6
Keith

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

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

재무 수치는 수세기에 걸친 종이와 펜 관행을 기반으로하며 관련 규칙이 있습니다. 그것들은 합리적으로 정확하지만 더 중요한 것은 재현 가능합니다. 다양한 숫자와 요율로 일하는 두 명의 회계사가 같은 숫자를 생각해 내야합니다. 불일치 할 수있는 모든 방은 사기의 방입니다.

따라서 재무 계산의 경우 정답은 산술에 능숙한 CPA와 동일한 답을 제공하는 것입니다. 이것은 IEEE 부동 소수점이 아닌 십진 산술입니다.

5
David Thornley

SQL 서버의 10 진 유형을 사용하십시오.

money 또는 float를 사용하지 마십시오.

돈은 소수점 이하 4 자리를 사용하고 소수점 이하 자리를 사용하는 것보다 빠릅니다 [~ # ~] but [~ # ~] 명백한 문제가 아니라 반올림 ( 이 연결 문제 참조 )

5
Mitch Wheat

내가 추천하는 것은 모든 것을 센트 단위로 저장하는 64 비트 정수를 사용하는 것입니다.

5
Joshua

부동 소수점은 정확한 표현이 아니며, 예를 들어 매우 크고 작은 값을 추가 할 때 정밀도 문제가 발생할 수 있습니다. 정밀도 문제가 충분히 드물지 않더라도 10 진수 유형이 통화에 권장되는 이유입니다.

명확히하기 위해 십진수 12,2 유형은 14 자리를 정확하게 저장하지만 float는 내부적으로 이진 표현을 사용하지 않습니다. 예를 들어 0.01은 부동 소수점 숫자로 정확하게 표현 될 수 없습니다. 가장 가까운 표현은 실제로 0.0099999998입니다.

4
Niall

내가 개발하는 데 도움을 준 금융 시스템의 경우 시스템의 "이자 발생"부분을 담당했습니다. 매일, 내 코드는 그날 잔고에 얼마나 많은이자가 발생했는지 계산했습니다.

이 계산을 위해서는 극도로 정확성과 충실도가 필요했습니다 (Oracle의 FLOAT를 사용했습니다). "십억 분의 1 페니"를 기록 할 수있었습니다.

이자가 "자본화"할 때 (즉,이자를 다시 귀하의 계좌로 상환) 금액은 페니로 반올림되었습니다. 계정 잔액의 데이터 유형은 소수점 이하 두 자리입니다. (실제로 많은 소수 자릿수에서 작동 할 수있는 다중 통화 시스템이므로 더 복잡했지만 항상 해당 통화의 "페니"로 반올림했습니다.) 예-손실과 이득의 "분수"가있는 곳이지만 컴퓨터 수치가 실현되었을 때 (돈을 지불하거나 지불 한 금액) 항상 실제 돈 가치였습니다.

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

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

4
Guy

Float를 돈으로 사용하는 유일한 이유는 정확한 답변에 관심이없는 경우입니다.

4
David Singer

회계 시스템에서 알아야 할 또 다른 사항은 아무도 테이블에 직접 액세스 할 수 없다는 것입니다. 즉, 회계 시스템에 대한 모든 액세스는 저장된 procs를 통해 이루어져야합니다. 이것은 SQ1 주입 공격뿐만 아니라 사기를 방지합니다. 사기를 저 지르려는 내부 사용자는 데이터베이스 테이블의 데이터를 직접 변경할 수 없어야합니다. 이것은 시스템의 중요한 내부 제어입니다. 불만을 품은 직원이 데이터베이스의 백엔드로 이동하여 수표 작성을 시작 하시겠습니까? 아니면 승인 권한이없는 승인되지 않은 공급 업체에 비용을 승인했다고 숨기십니까? 전체 조직의 두 사람 만 재무 데이터베이스, dba 및 그의 백업에있는 데이터에 직접 액세스 할 수 있어야합니다. 많은 수의 dbas가 있다면, 그들 중 두 명만이이 액세스 권한을 가져야합니다.

프로그래머가 회계 시스템에서 플로트를 사용한 경우 내부 제어 개념에 익숙하지 않고 프로그래밍 노력에서 고려하지 않았기 때문에 이것을 언급합니다.

3
HLGEM

소수를 사용하는 것보다 평범한 오래된 정수 (또는 어쩌면 어떤 종류의 bigint)를 사용하는 것보다 낫습니다. 이렇게하면 항상 가능한 최고의 정확도를 가지지 만 정밀도를 지정할 수 있습니다. 예를 들어 숫자 1001.00 형식은 다음과 같습니다.

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

정밀도를 높이려면 100을 10 ^ n과 같이 더 큰 값으로 변경할 수 있습니다. 여기서 n은 소수입니다.

3
Peter Stuifzand

100 개의 분수 n/100 중에서 n은 0 <= n 및 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;
}
2
Lars Bohl

.Net의 Money 유형과 같은 것을 항상 작성할 수 있습니다.

이 기사를 살펴보십시오. CLR의 돈 유형 -저자는 제 의견으로는 훌륭한 작업을 수행했습니다.

2
Tomer Pintel

화폐 가치를 저장하기 위해 SQL의 돈 유형을 사용하고있었습니다. 최근에, 나는 많은 온라인 지불 시스템과 협력해야했고 그들 중 일부는 화폐 가치를 저장하기 위해 정수를 사용한다는 것을 알아 냈습니다. 현재 프로젝트와 새 프로젝트에서 정수를 사용하기 시작 했으며이 솔루션에 만족합니다.

2
George

통화 값에 일정한 형태의 고정 소수점 표현을 사용하려고 할 것입니다. 또한 Banker의 반올림 ( "반올림 짝수"이라고도 함)을 조사하려고합니다. 일반적인 "반올림"방법에 존재하는 편향을 피합니다.

1
user6931

금액 데이터를 사용하여 금액을 저장하는 것을 고려 했습니까?

10 진수가 1 바이트를 더 차지한다는 단점에 대해서는 신경 쓰지 않는다고 말할 것입니다. 백만 개의 행에서는 1MB 만 더 사용하며 요즘에는 스토리지가 매우 저렴합니다.

1
Espo

무엇을 하든지 반올림 오류에주의해야합니다. 표시하는 것보다 더 큰 정밀도를 사용하여 계산하십시오.

1
1800 INFORMATION

회계사는 귀하의 반올림 방법을 통제하기를 원할 것입니다. float을 사용하면 일반적으로 FORMAT () 형식 문을 사용하여 계속 반올림합니다. 이는 원하는 방식이 아닙니다 (대신 바닥/천장 사용).

Float 또는 real 대신 사용해야하는 통화 데이터 유형 (money, smallmoney)이 있습니다. 소수점 이하 자릿수 (12,2)를 저장하면 반올림이 제거되지만 중간 단계에서 제거 할 수 있습니다. 실제로 재무 응용 프로그램에서 원하지 않는 것은 아닙니다.

0
David T. Macknet

이것은 float 및 decimal을 사용할 때 를 설명하는 훌륭한 기사입니다. Float은 대략적인 값을 저장하고 decimal은 정확한 값을 저장합니다.

요약하면, 돈과 같은 정확한 값은 십진수를 사용해야하고 과학적인 측정과 같은 대략적인 값은 float을 사용해야합니다.

다음은 플로트와 십진법 모두 정밀도를 잃을 수 있음을 보여주는 흥미로운 예입니다. 정수가 아닌 숫자를 더한 다음 같은 수의 float를 빼면 정밀도가 떨어지지 만 10 진수는 그렇지 않습니다.

    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
0
BrokeMyLegBiking

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

0
Roel Vlemmings

부동 소수점 숫자는 only 이진수 부동 소수점의 경우 음수의 배수의 합인 숫자를 나타낼 수 있습니다. 물론 2입니다.

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

부동 소수점은 결과의 스케일이 중요한 계산에 적합합니다. 소수의 소수 자릿수까지 정확하려고하는 것은 나쁜 선택입니다.

0
Mike Dimmick