your programing

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

lovepro 2020. 10. 15. 08:18
반응형

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


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

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

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

어느 쪽의 장단점은 무엇입니까?

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

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

Pro는 Decimal이 9 바이트를 차지하는 디스크에서 8 바이트 만 차지하는 Float입니다 (Decimal 12,2).


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

대답은 간단합니다. 절대 뜨지 않습니다. 절대 !

수레가에 따라 한 IEEE 754 항상 바이너리 만 새로운 표준 IEEE 754R은 소수점 형식을 정의했다. 소수 이진 부분의 대부분은 정확한 십진 표현과 같을 수 없습니다.
이진수는 m/2^n( m, n양의 정수), 10 진수는 m/(2^n*5^n).
바이너리에는 prime이 없기 때문에 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.05000000005 센트를 의미한다는 것을 알 수 있지만 컴퓨터는 그것을 인식하지 못하고 0.4999... 내림 (잘못) 및 0.5000... 올림 (오른쪽 ).
부동 소수점 계산의 결과에는 항상 작은 오류 항이 포함되어 있으므로 결정은 순전히 행운입니다. 이진수로 십진수 반올림 처리를 원하면 절망적입니다.

확신이 없습니까? 당신은 당신의 계정 시스템에서 모든 것이 완벽하게 괜찮다고 주장합니까?
자산과 부채가 같습니까? 좋아, 그런 다음 각 항목의 주어진 형식화 된 숫자를 가져 와서 구문 분석하고 독립적 인 십진수 시스템으로 합산하십시오! 형식화 된 합계와 비교하십시오.
죄송합니다. 뭔가 잘못 되었나요?

그 계산을 위해 극도의 정확성과 충실도가 필요했습니다 (우리는 Oracle의 FLOAT를 사용했습니다). "10 억 분의 1 페니"가 저축되는 것을 기록 할 수있었습니다.

이 오류에 대해 도움이되지 않습니다. 모든 사람들이 자동으로 컴퓨터의 합이 옳다고 가정하기 때문에 사실상 아무도 독립적으로 확인하지 않습니다.


이 사진에 대한 답변 :

photo1, CO

이것은 또 다른 상황입니다. Northampton에서 온 남자가 0 달러와 0 센트를 지불하지 않으면 집이 압수 될 것이라는 편지를 받았습니다!

photo2, CO


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

현재 거의 쓸모없는 빠른 x87 fp를 노출하기 위해 Floats / doubles가 존재합니다. 계산의 정확성에 관심이 있거나 한계를 완전히 보상하지 않는 경우에는 사용하지 마십시오.


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


회계사에게 물어보세요! 플로트를 사용하면 눈살을 찌푸 릴 것입니다. 이전에 게시 된 일부와 마찬가지로 정확성에 신경 쓰지 않는 경우에만 float를 사용하십시오. 돈에 관해서는 항상 반대 하겠지만.

회계 소프트웨어에서는 플로트가 허용되지 않습니다. 소수점 4 자리에 소수점을 사용합니다.


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

예를 들어 1/3을 십진수로 저장할 수 없습니다. 0.3333333333 ... (등)

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

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

이 밑이 2 인 지수를 사용하면 다음과 같은 이상한 비합리적인 숫자가 생성됩니다.

1.1을 실수로 변환 한 다음 다시 변환하면 결과는 다음과 같습니다. 1.0999999999989

이것은 1.1의 이진 표현이 실제로 154811237190861 x 2 ^ -47이기 때문에 이중보다 더 많이 처리 할 수 ​​있습니다.

이 문제에 대한 자세한 내용은 내 블로그 에서 확인할 수 있지만 기본적으로 저장을 위해서는 소수를 사용하는 것이 좋습니다.

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

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

그러나 소수는 어떤 종류의 수학에도 적합하지 않습니다. 예를 들어 소수의 거듭 제곱에 대한 기본 지원이 없습니다.


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

이나 부유물을 사용하지 마십시오 .

돈이 더 빨리 진수 사용하는 것보다, 4 소수점을 사용 하지만 일부 분명 앓고과 둥근 일부 그리 명확하지 문제를 ( 이 연결 문제를 참조 )


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


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

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

재무 수치는 관련 관례와 함께 수세기에 걸친 종이와 펜 관행을 기반으로합니다. 합리적으로 정확하지만 더 중요한 것은 재현 가능하다는 것입니다. 다양한 숫자와 요율로 작업하는 두 명의 회계사가 동일한 숫자를 제시해야합니다. 불일치의 여지는 사기의 여지입니다.

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


돈을 위해 Float를 사용하는 유일한 이유는 정확한 답변에 관심이 없기 때문입니다.


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

To clarify, the decimal 12,2 type will store those 14 digits exactly, whereas the float will not as it uses a binary representation internally. For example, 0.01 cannot be represented exactly by a floating point number - the closest representation is actually 0.0099999998


For a banking system I helped develop, I was responsible for the "interest accrual" part of the system. Each day, my code calculated how much interest had been accrued (earnt) on the balance that day.

For that calculation, extreme accuracy and fidelity was required (we used Oracle's FLOAT) so we could record the "billionth's of a penny" being accrued.

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

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

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


Even better than using decimals is using just plain old integers (or maybe some kind of bigint). This way you always have the highest accuracy possible, but the precision can be specified. For example the number 100 could mean 1.00, which is formatted like this:

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

If you like to have more precision, you can change the 100 to a bigger value, like: 10 ^ n, where n is the number of decimals.


Another thing you should be aware of in accounting systems is that no one should have direct access to the tables. This means all access to the accounting system must be through stored procs. This is prevent fraud not just SQl injection attacks. An internal user who wants to commit fraud should not have the ability to directly change data in the database tables, ever. This is a critcal internal control on your system. Do you really want some disgruntled employee to go to the backend of your database and have it start wrting them checks? Or hide that they approved an expense to an unauthorized vendor when they don't have approval authority? Only two people in your whole organization should be able to directly access data in your financial database, your dba and his backup. If you have many dbas, only two of them should have this access.

I mention this because if your programmers used float in an accounting system, likely they are completely unfamiliar with the idea of internal controls and did not consider them in their programming effort.


You can always write something like a Money type for .Net.

Take a look at this article: A Money type for the CLR - The author did an excellent work in my opinion.


I had been using SQL's money type for storing monetary values. Recently, I've had to work with a number of online payment systems and have noticed that some of them use integers for storing monetary values. In my current and new projects I've started using integers and I'm pretty content with this solution.


Out of the 100 fractions n/100, where n is a natural number such that 0 <= n and n < 100, only four can be represented as floating point numbers. Take a look at the output of this C program:

#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;
}

Have you considered using the money-data type to store dollar-amounts?

Regarding the Con that decimal takes up one more byte, I would say don't care about it. In 1 million rows you will only use 1 more MB and storage is very cheap these days.


Whatever you do, you need to be careful of rounding errors. Calculate using a greater degree of precision than you display in.


You will probably want to use some form of fixed point representation for currency values. You will also want to investigate Banker's rounding (also known as "round half even".) It avoids bias that exist in the usual "round half up" method.


Your accountants will want to control how you round. Using float means that you'll be constantly rounding, usually with a FORMAT() type statement, which isn't the way you want to do it (use floor / ceiling instead).

You have currency datatypes (money, smallmoney), which should be used instead of float or real. Storing decimal (12,2) will eliminate your roundings, but will also eliminate them during intermediate steps - which really isn't what you'll want at all in a financial application.


Always use Decimal. Float will give you inaccurate values due to rounding issues.


Floating point numbers can only represent numbers that are a sum of negative multiples of the base - for binary floating point, of course, that's two.

There are only four decimal fractions representable precisely in binary floating point: 0, 0.25, 0.5 and 0.75. Everything else is an approximation, in the same way that 0.3333... is an approximation for 1/3 in decimal arithmetic.

Floating point is a good choice for computations where the scale of the result is what is important. It's a bad choice where you're trying to be accurate to some number of decimal places.


This is an excellent article describing when to use float and decimal. Float stores an approximate value and decimal stores an exact value.

In summary, exact values like money should use decimal, and approximate values like scientific measurements should use float.

다음은 float와 decimal이 모두 정밀도를 잃을 수 있음을 보여주는 흥미로운 예입니다. 정수가 아닌 숫자를 더한 다음 동일한 숫자 부동 소수점을 빼면 정밀도가 떨어지고 소수는 그렇지 않습니다.

    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

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

반응형