it-swarm-vi.tech

Sử dụng Float hoặc Decimal cho Số tiền ứng dụng kế toán?

Chúng tôi đang viết lại Hệ thống kế toán kế thừa của chúng tôi trong VB.NET và SQL Server. Chúng tôi đã đưa vào một nhóm lập trình viên .NET/SQL mới để viết lại. Hầu hết hệ thống đã được hoàn thành với số tiền Dollar sử dụng Floats. Ngôn ngữ hệ thống cũ, tôi đã lập trình, không có Float nên có lẽ tôi đã sử dụng Thập phân.

Đề nghị của bạn là gì?

Nên sử dụng kiểu dữ liệu Float hoặc Decimal cho số tiền đô la?

Một số ưu và nhược điểm cho một trong hai là gì?

Một Con được đề cập trong scrum hàng ngày của chúng tôi là bạn phải cẩn thận khi tính toán số tiền trả về kết quả vượt quá hai vị trí thập phân. Có vẻ như bạn sẽ phải làm tròn số tiền đến hai vị trí thập phân.

Một Con khác là tất cả các màn hình và số lượng in phải có Tuyên bố định dạng hiển thị hai vị trí thập phân. Tôi đã nhận thấy một vài lần điều này không được thực hiện và số tiền có vẻ không chính xác. (tức là 10,2 hoặc 10,2546)

Một pro là Float chỉ chiếm 8 byte trên đĩa trong đó Decimal sẽ chiếm 9 byte (Decimal 12,2) 

74
Gerhard Weiss

Nên sử dụng kiểu dữ liệu Float hoặc Decimal cho số tiền đô la?

Câu trả lời rất dễ. Không bao giờ nổi. KHÔNG BAO GIỜ !

Các phao được theo IEEE 754 luôn luôn là nhị phân, chỉ có các định dạng thập phân chuẩn IEEE 754R được xác định. Nhiều phần nhị phân phân số không bao giờ có thể bằng biểu diễn thập phân chính xác.
Bất kỳ số nhị phân nào cũng có thể được viết dưới dạng m/2^n (m, n số nguyên dương), bất kỳ số thập phân nào dưới dạng m/(2^n*5^n).
Vì các nhị phân thiếu số nguyên tố factor 5, tất cả các số nhị phân có thể được biểu diễn chính xác bằng số thập phân, nhưng không phải ngược lại.

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

Vì vậy, bạn kết thúc với một số cao hơn hoặc thấp hơn số thập phân đã cho. Luôn luôn.

Tại sao lại là vấn đề đó ? Làm tròn số.
Làm tròn bình thường có nghĩa là 0..4 xuống, 5..9 trở lên. Vì vậy, nó là {hiện nếu kết quả là Hoặc là 0.049999999999.... hoặc 0.0500000000... Bạn có thể biết rằng nó có nghĩa là 5 xu, nhưng máy tính không biết điều đó và làm tròn 0.4999 .. . xuống (sai) và 0.5000... lên (phải).
Cho rằng kết quả của các phép tính dấu phẩy động luôn chứa các điều khoản lỗi nhỏ, quyết định hoàn toàn là may mắn. Sẽ là vô vọng nếu bạn muốn xử lý vòng tròn chẵn đến thập phân với các số nhị phân.

Không tin tưởng? Bạn nhấn mạnh rằng trong hệ thống tài khoản của bạn mọi thứ hoàn toàn ổn?
Tài sản và nợ phải trả bằng nhau? Ok, sau đó lấy từng số được định dạng của từng mục, phân tích chúng và tính tổng chúng với một hệ thập phân độc lập! So sánh số đó với tổng được định dạng.
.__ Rất tiếc, có gì đó không ổn phải không? 

Đối với tính toán đó, cần phải có độ chính xác và độ trung thực cao (chúng tôi đã sử dụng Oracle FLOAT) để chúng tôi có thể ghi lại "một phần tỷ của một xu".

Không giúp chống lại lỗi này. Bởi vì tất cả mọi người tự động cho rằng máy tính tổng hợp đúng, thực tế không ai kiểm tra độc lập.

105
TSK
41
Nakilon

Trước tiên, bạn nên đọc cái này Điều mà mọi nhà khoa học máy tính nên biết về số học dấu phẩy động . Sau đó, bạn thực sự nên cân nhắc sử dụng một số loại điểm cố định/số chính xác tùy ý gói (ví dụ: Java BigNum, mô-đun thập phân python) nếu không bạn sẽ gặp phải một thế giới bị tổn thương. Sau đó tìm hiểu xem sử dụng kiểu thập phân SQL gốc là đủ. 

Phao/đôi tồn tại (ed) để lộ x87 fp nhanh hiện đã lỗi thời. Đừng sử dụng chúng nếu bạn quan tâm đến tính chính xác của các tính toán và/hoặc không hoàn toàn bù đắp cho những hạn chế của chúng.

22
Rich Schuler

Cũng giống như một cảnh báo bổ sung, SQL Server và khung .Net sử dụng thuật toán mặc định khác để làm tròn. Hãy chắc chắn rằng bạn kiểm tra tham số MidPointRounding trong Math.Round (). Khung .Net sử dụng thuật toán Bankers theo mặc định và SQL Server sử dụng Làm tròn thuật toán đối xứng. Kiểm tra bài viết Wikipedia tại đây

10
Darrel Miller

Hỏi kế toán của bạn! Họ sẽ nhăn mặt khi bạn sử dụng phao. Giống như một số được đăng trước đó, chỉ sử dụng float nếu bạn không quan tâm đến độ chính xác. Mặc dù tôi sẽ luôn chống lại nó khi nói đến tiền.

Trong phần mềm kế toán KHÔNG được chấp nhận một float. Sử dụng số thập phân với 4 điểm thập phân.

7
Ricardo C

Điểm nổi có số vô tỷ bất ngờ.

Chẳng hạn, bạn không thể lưu trữ 1/3 dưới dạng thập phân, nó sẽ là 0,333333333 ... (v.v.)

Phao thực sự được lưu trữ dưới dạng giá trị nhị phân và lũy thừa 2 số mũ.

Vì vậy, 1,5 được lưu trữ dưới dạng 3 x 2 đến -1 (hoặc 3/2)

Ví dụ, sử dụng các số mũ cơ sở 2 này tạo ra một số số vô tỷ lẻ:

Chuyển đổi 1.1 thành float và sau đó chuyển đổi lại, kết quả của bạn sẽ giống như: 1.0999999999989

Điều này là do biểu diễn nhị phân của 1.1 thực sự là 154811237190861 x 2 ^ -47, nhiều hơn gấp đôi có thể xử lý.

Thông tin thêm về vấn đề này trên blog của tôi , nhưng về cơ bản, để lưu trữ, bạn tốt hơn với số thập phân.

Trên máy chủ Microsoft SQL, bạn có kiểu dữ liệu money - điều này thường tốt nhất cho việc lưu trữ tài chính. Nó chính xác đến 4 vị trí thập phân.

Đối với các tính toán, bạn có nhiều vấn đề hơn - sự thiếu chính xác là một phần rất nhỏ, nhưng đặt nó vào một hàm năng lượng và nó nhanh chóng trở nên quan trọng. 

Tuy nhiên, số thập phân không tốt cho bất kỳ loại toán nào - chẳng hạn, không có hỗ trợ riêng cho các lũy thừa thập phân.

6
Keith

Một chút nền tảng ở đây ....

Không có hệ thống số có thể xử lý tất cả các số thực một cách chính xác. Tất cả đều có những hạn chế của chúng, và điều này bao gồm cả dấu phẩy động chuẩn và dấu thập phân có chữ ký của IEEE. Điểm nổi của IEEE chính xác hơn trên mỗi bit được sử dụng, nhưng điều đó không quan trọng ở đây.

Số tài chính dựa trên nhiều thế kỷ thực hành bằng giấy và bút, với các quy ước liên quan. Chúng chính xác một cách hợp lý, nhưng, quan trọng hơn, chúng có thể tái tạo. Hai kế toán viên làm việc với nhiều con số và tỷ lệ khác nhau sẽ đưa ra cùng một con số. Bất kỳ phòng cho sự khác biệt là phòng cho gian lận.

Do đó, đối với các tính toán tài chính, câu trả lời đúng là bất cứ điều gì đưa ra câu trả lời giống như CPA, người giỏi về số học. Đây là số học thập phân, không phải là dấu phẩy động của IEEE.

5
David Thornley

Sử dụng loại thập phân của máy chủ SQL.

Không sử dụng tiền hoặc float.

tiền sử dụng 4 chữ số thập phân, nhanh hơn so với sử dụng thập phân NHƯNG bị một số vấn đề rõ ràng và một số vấn đề không rõ ràng với làm tròn ( xem vấn đề kết nối này

5
Mitch Wheat

Những gì tôi muốn giới thiệu là sử dụng số nguyên 64 bit lưu trữ toàn bộ bằng xu.

5
Joshua

Phao không phải là biểu diễn chính xác, các vấn đề chính xác là có thể, ví dụ như khi thêm các giá trị rất lớn và rất nhỏ. Đó là lý do tại sao các loại thập phân được khuyến nghị cho tiền tệ, mặc dù vấn đề chính xác có thể đủ hiếm.

Để làm rõ, loại 12,2 thập phân sẽ lưu trữ chính xác 14 chữ số đó, trong khi float sẽ không sử dụng biểu diễn nhị phân bên trong. Ví dụ: 0,01 không thể được biểu diễn chính xác bằng số dấu phẩy động - đại diện gần nhất thực sự là 0,0099999998

4
Niall

Đối với một hệ thống ngân hàng mà tôi đã giúp phát triển, tôi chịu trách nhiệm cho phần "tích lũy lãi suất" của hệ thống. Mỗi ngày, mã của tôi tính toán số tiền lãi đã được tích lũy (số tiền) vào số dư ngày hôm đó.

Đối với tính toán đó, cần có độ chính xác và độ trung thực cao (chúng tôi đã sử dụng FLOAT của Oracle) để chúng tôi có thể ghi lại "một phần tỷ của một xu" được tích lũy.

Khi nói đến việc "tận dụng" tiền lãi (tức là trả lại tiền lãi vào tài khoản của bạn), số tiền được làm tròn thành đồng xu. Kiểu dữ liệu cho số dư tài khoản là hai chữ số thập phân. (Trên thực tế, nó phức tạp hơn vì nó là một hệ thống đa tiền tệ có thể hoạt động ở nhiều vị trí thập phân - nhưng chúng tôi luôn làm tròn đến "đồng xu" của loại tiền đó). Có - ở đó "phân số" của mất và thu được, nhưng khi các số liệu máy tính được hiện thực hóa (tiền được trả hoặc được trả) thì đó luôn là giá trị tiền THỰC SỰ.

Điều này làm hài lòng các kế toán viên, kiểm toán viên và người kiểm tra.

Vì vậy, hãy kiểm tra với khách hàng của bạn. Họ sẽ cho bạn biết các quy tắc và thông lệ ngân hàng/kế toán của họ.

4
Guy

Lý do duy nhất để sử dụng Float để kiếm tiền là nếu bạn không quan tâm đến câu trả lời chính xác. 

4
David Singer

Một điều khác bạn cần lưu ý trong các hệ thống kế toán là không ai nên có quyền truy cập trực tiếp vào các bảng. Điều này có nghĩa là tất cả quyền truy cập vào hệ thống kế toán phải thông qua các procs được lưu trữ. Điều này là ngăn chặn gian lận không chỉ các cuộc tấn công tiêm chích. Người dùng nội bộ muốn thực hiện hành vi gian lận không nên có khả năng thay đổi trực tiếp dữ liệu trong các bảng cơ sở dữ liệu. Đây là một kiểm soát nội bộ phê bình trên hệ thống của bạn. Bạn có thực sự muốn một số nhân viên bất mãn đi đến phần cuối của cơ sở dữ liệu của bạn và để nó bắt đầu kiểm tra họ không? Hoặc che giấu rằng họ đã phê duyệt một chi phí cho một nhà cung cấp trái phép khi họ không có thẩm quyền phê duyệt? Chỉ có hai người trong toàn bộ tổ chức của bạn có thể truy cập trực tiếp dữ liệu trong cơ sở dữ liệu tài chính, dba của bạn và bản sao lưu của anh ấy. Nếu bạn có nhiều dbas, chỉ hai trong số họ nên có quyền truy cập này.

Tôi đề cập đến điều này bởi vì nếu các lập trình viên của bạn sử dụng float trong một hệ thống kế toán, có khả năng họ hoàn toàn xa lạ với ý tưởng kiểm soát nội bộ và không xem xét chúng trong nỗ lực lập trình của họ.

3
HLGEM

Thậm chí tốt hơn so với việc sử dụng số thập phân là chỉ sử dụng các số nguyên cũ đơn giản (hoặc có thể là một số loại hình lớn). Bằng cách này, bạn luôn có độ chính xác cao nhất có thể, nhưng độ chính xác có thể được chỉ định. Ví dụ: số 100 có thể có nghĩa là 1.00, được định dạng như thế này:

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

Nếu bạn muốn có độ chính xác cao hơn, bạn có thể thay đổi 100 thành giá trị lớn hơn, như: 10 ^ n, trong đó n là số thập phân.

3
Peter Stuifzand

Trong số 100 phân số n/100, trong đó n là số tự nhiên sao cho 0 <= n và n <100, chỉ có bốn số có thể được biểu diễn dưới dạng số dấu phẩy động. Hãy xem đầu ra của chương trình C này:

#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

Bạn luôn có thể viết một cái gì đó giống như loại Tiền cho .Net.

Hãy xem bài viết này: Một loại tiền cho CLR - Tác giả đã làm một tác phẩm xuất sắc theo ý kiến ​​của tôi.

2
Tomer Pintel

Tôi đã sử dụng loại tiền của SQL để lưu trữ các giá trị tiền tệ. Gần đây, tôi đã phải làm việc với một số hệ thống thanh toán trực tuyến và nhận thấy rằng một số trong số họ sử dụng số nguyên để lưu trữ giá trị tiền tệ. Trong các dự án hiện tại và mới của tôi, tôi đã bắt đầu sử dụng số nguyên và tôi khá hài lòng với giải pháp này.

2
George

Bạn có thể sẽ muốn sử dụng một số hình thức biểu diễn điểm cố định cho các giá trị tiền tệ. Bạn cũng sẽ muốn điều tra làm tròn Ngân hàng (còn được gọi là "làm tròn một nửa chẵn".) Nó tránh sự thiên vị tồn tại trong phương pháp "làm tròn một nửa" thông thường.

1
user6931

Bạn đã cân nhắc sử dụng loại dữ liệu tiền để lưu trữ số tiền chưa?

Về Con số thập phân chiếm thêm một byte, tôi sẽ nói đừng quan tâm đến nó. Trong 1 triệu hàng bạn sẽ chỉ sử dụng thêm 1 MB và dung lượng lưu trữ rất rẻ trong những ngày này.

1
Espo

Dù bạn làm gì, bạn cần cẩn thận với các lỗi làm tròn. Tính toán sử dụng mức độ chính xác cao hơn mức bạn hiển thị.

1
1800 INFORMATION

Kế toán của bạn sẽ muốn kiểm soát cách bạn làm tròn. Sử dụng float có nghĩa là bạn sẽ liên tục làm tròn, thường là với câu lệnh loại FORMAT (), đây không phải là cách bạn muốn làm (thay vào đó sử dụng sàn/trần).

Bạn có các kiểu dữ liệu tiền tệ (tiền, smallmoney), nên được sử dụng thay vì float hoặc real. Lưu trữ thập phân (12,2) sẽ loại bỏ các vòng của bạn, nhưng cũng sẽ loại bỏ chúng trong các bước trung gian - đây thực sự không phải là điều bạn muốn trong một ứng dụng tài chính.

0
David T. Macknet

Đây là một bài viết tuyệt vời mô tả khi nào nên sử dụng float và thập phân . Float lưu trữ một giá trị gần đúng và thập phân lưu trữ một giá trị chính xác.

Tóm lại, các giá trị chính xác như tiền nên sử dụng số thập phân và các giá trị gần đúng như các phép đo khoa học nên sử dụng float. 

Dưới đây là một ví dụ thú vị cho thấy cả float và thập phân đều có khả năng mất độ chính xác. Khi thêm một số không phải là số nguyên và sau đó trừ đi số float đó sẽ dẫn đến mất độ chính xác trong khi số thập phân thì không:

    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

Khi nhân một số nguyên không và chia cho cùng một số đó, số thập phân sẽ mất độ chính xác trong khi số float thì không.

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

Luôn luôn sử dụng số thập phân. Float sẽ cung cấp cho bạn các giá trị không chính xác do các vấn đề làm tròn.

0
Roel Vlemmings

Số dấu phẩy động có thể chỉ đại diện cho các số là tổng bội số âm của cơ sở - đối với dấu phẩy động nhị phân, tất nhiên, đó là hai.

Chỉ có bốn phân số thập phân có thể biểu diễn chính xác trong dấu phẩy động nhị phân: 0, 0,25, 0,5 và 0,75. Mọi thứ khác là một xấp xỉ, theo cùng một cách mà 0,3333 ... là một xấp xỉ bằng 1/3 trong số học thập phân.

Điểm nổi là một lựa chọn tốt cho các tính toán trong đó thang đo của kết quả là điều quan trọng. Đó là một lựa chọn tồi khi bạn đang cố gắng chính xác đến một số vị trí thập phân.

0
Mike Dimmick