Có một đại diện dữ liệu duy nhất hoạt động cho tất cả các loại tiền tệ (ngay cả những loại khác với Đô la, Euro và Bảng Anh) không?


12

Tôi có thể tìm thấy nhiều câu hỏi về các thư viện để sử dụng để đại diện cho số tiền bằng một số loại tiền tệ. Và về vấn đề cũ về lý do tại sao bạn không nên lưu trữ tiền tệ dưới dạng số dấu phẩy động của IEEE 754. Nhưng tôi dường như không thể tìm thấy gì hơn. Chắc chắn còn nhiều điều cần biết về tiền tệ trong sử dụng thế giới thực. Tôi đặc biệt quan tâm đến những gì bạn cần biết để thể hiện nó trong sử dụng vật lý (ví dụ: với đồng đô la, bạn không bao giờ có độ chính xác dưới 0,01 đô la, cho phép biểu diễn dưới dạng số nguyên xu).

Nhưng thật khó để đưa ra các giả định về mức độ linh hoạt của chương trình của bạn khi các loại tiền tệ duy nhất bạn biết là các loại tiền phổ biến của phương Tây (chẳng hạn như đồng đô la, euro và bảng Anh). Những gì khác là kiến ​​thức có liên quan trong một quan điểm lập trình thuần túy? Tôi không quan tâm đến chủ đề chuyển đổi.

Đặc biệt, những gì chúng ta cần biết để có thể lưu trữ giá trị bằng một số loại tiền và in chúng ra?


2
Không phải tất cả các lập trình viên làm việc trong các ngành công nghiệp thao túng số lượng tiền tệ.
whatsisname 17/03/2017

4
Ồ dĩ nhiên rồi. Nhưng điều đó có thể nói về hầu hết mọi thứ. Tôi nghĩ rằng chúng ta có thể cho rằng những người thấy câu hỏi này hữu ích sẽ là những người làm việc với tiền tệ.
Kat

5
Tôi đã thực hiện rất nhiều công việc phát triển cho các ngân hàng và các công ty dịch vụ tài chính khác ở NYC. Và tôi có thể đảm bảo khá nhiều cho bạn rằng không có câu trả lời "dạng đóng" cho câu hỏi của bạn. Bạn cũng có thể hỏi, "tôi phải biết bao nhiêu toán?" Ví dụ, trở lại những năm 1990, giá cổ phiếu đã tăng từ thứ tám và thứ 256 sang số thập phân, đòi hỏi phải lập trình lại rất nhiều. Ai có thể đoán điều đó sẽ xảy ra? Bạn chỉ cần hiểu doanh nghiệp mà các ứng dụng của bạn đang hỗ trợ và cách thể hiện tốt nhất dữ liệu (trong trường hợp này là tiền tệ) để hỗ trợ các nhu cầu kinh doanh đó.
John Forkosh 17/03/2017

4
0,02 của tôi: Giá là một thứ. Tiền tệ là khác.
Machado

3
Tôi nghĩ, ồ, phải có một mẫu số chung cho tất cả các loại tiền tệ. Nhưng có lẽ là không. Đồng xu hiện tại là 1⁄100 pound, nhưng là 1⁄240 pound. Vì vậy, bạn không chỉ có phân chia 1/240 mà còn có ngày chuyển đổi và có thể tỷ giá hối đoái cho đồng xu cũ chưa được chuyển đổi. vi.wikipedia.org/wiki/Penny_sterling Thậm chí đừng để tôi bắt đầu với vỏ đạn! vi.wikipedia.org/wiki/Shell_money hoặc thực tế là tiền đòi hỏi niềm tin để trở thành hiện thực: en.wikipedia.org/wiki/Money Câu hỏi tuyệt vời ngay cả khi nó không phù hợp với StackExchange!
GlenPeterson

Câu trả lời:


24

ví dụ: với đồng đô la, bạn không bao giờ có độ chính xác dưới 0,01 đô la

Ồ vậy sao nhập mô tả hình ảnh ở đây

vấn đề cũ về lý do tại sao bạn không nên lưu trữ tiền tệ dưới dạng số dấu phẩy động IEEE 754.

nhập mô tả hình ảnh ở đây

Xin vui lòng lưu trữ inch trong số dấu phẩy động IEEE 754 . Họ lưu trữ chính xác như bạn mong đợi.

Xin vui lòng lưu trữ bất kỳ số tiền nào trong các số dấu phẩy động IEEE 754 mà bạn có thể lưu trữ bằng cách sử dụng các dấu chia chia thước thành các phân số của một inch.

Tại sao? Bởi vì khi bạn sử dụng IEEE 754 , đó là cách bạn lưu trữ nó.

Điều về inch là chúng được chia thành hai nửa. Điều về hầu hết các loại tiền tệ là chúng được chia thành một phần mười (một số loại không nhưng hãy tập trung).

Sự khác biệt này sẽ không gây nhầm lẫn ngoại trừ, đối với hầu hết các ngôn ngữ lập trình, đầu vào và đầu ra từ các số dấu phẩy động của IEEE 754 được biểu thị bằng số thập phân! Điều này rất lạ bởi vì chúng không được lưu trữ trong số thập phân.

Bởi vì điều này bạn không bao giờ có thể thấy các bit làm những điều kỳ lạ khi bạn yêu cầu máy tính lưu trữ 0.1. Bạn chỉ thấy sự kỳ lạ khi bạn làm toán chống lại nó và nó có những lỗi lạ.

Từ java hiệu quả của Josh Bloch :

System.out.println(1.03 - .42);

Sản xuất 0.6100000000000001

Điều gì nói nhiều nhất về điều này không phải là 1cách ngồi phía bên phải. Đó là những con số kỳ lạ phải được sử dụng để có được nó. Thay vì sử dụng ví dụ phổ biến nhất 0.1, chúng ta phải sử dụng một ví dụ cho thấy vấn đề và tránh làm tròn sẽ che giấu nó.

Ví dụ, tại sao điều này làm việc?

System.out.println(.01 - .02);

Sản xuất -0.01

Bởi vì chúng tôi đã gặp may mắn.

Tôi ghét những vấn đề khó chẩn đoán vì đôi khi tôi gặp "may mắn".

IEEE 754 đơn giản là không thể lưu trữ chính xác 0,1. Nhưng nếu bạn yêu cầu nó lưu 0,1 và sau đó yêu cầu nó in thì nó sẽ hiển thị 0,1 và bạn sẽ nghĩ mọi thứ đều ổn. Điều đó không ổn, nhưng bạn không thể thấy điều đó bởi vì nó làm tròn để trở về 0,1.

Một số người nhầm lẫn giữa những người khác bằng cách gọi những sai lệch làm tròn số sai lệch này. Không, đây không phải là lỗi làm tròn. Việc làm tròn đang thực hiện những gì nó được yêu cầu và biến những gì không phải là số thập phân thành số thập phân để nó có thể in trên màn hình.

Nhưng điều này che giấu sự không phù hợp giữa cách hiển thị số và cách lưu trữ. Lỗi không xảy ra khi làm tròn số xảy ra. Nó xảy ra khi bạn quyết định đặt một số vào một hệ thống không thể lưu trữ chính xác và cho rằng nó được lưu trữ chính xác khi không.

Không ai mong muốn π sẽ lưu trữ chính xác trong một máy tính và họ quản lý để làm việc với nó tốt. Vì vậy, vấn đề thậm chí không phải là về độ chính xác. Đó là về độ chính xác dự kiến. Máy tính hiển thị một phần mười 0.1giống như máy tính của chúng tôi, vì vậy chúng tôi hy vọng chúng sẽ lưu trữ một phần mười hoàn hảo như cách máy tính của chúng tôi làm. Họ không. Đó là điều đáng ngạc nhiên, vì máy tính đắt hơn.

Hãy để tôi chỉ cho bạn sự không phù hợp:

nhập mô tả hình ảnh ở đây

Lưu ý rằng 1/2 và 0,5 xếp hàng hoàn hảo. Nhưng 0,1 không xếp hàng. Chắc chắn bạn có thể tiến gần hơn nếu bạn tiếp tục chia cho 2 nhưng bạn sẽ không bao giờ đánh chính xác. Và chúng ta cần nhiều bit hơn mỗi lần chúng ta chia cho 2. Vì vậy, đại diện 0,1 với bất kỳ hệ thống nào chia cho 2 cần một số lượng bit vô hạn. Ổ cứng của tôi không lớn như vậy.

Vì vậy, IEEE 754 ngừng cố gắng khi hết bit. Thật tuyệt vì tôi cần chỗ trên ổ cứng để ... ảnh gia đình. Không thực sự. Nhưng bưc ảnh gia đinh. : P

Dù sao, những gì bạn gõ và những gì bạn nhìn thấy là số thập phân (bên phải) nhưng những gì bạn lưu trữ là nhị phân (bên trái). Đôi khi những điều đó là hoàn toàn giống nhau. Đôi khi họ không. Đôi khi, nó giống như khi chúng không giống nhau. Đó là làm tròn.

Đặc biệt, những gì chúng ta cần biết để có thể lưu trữ giá trị bằng một số loại tiền và in ra?

Xin vui lòng, nếu bạn đang xử lý tiền dựa trên số thập phân của tôi, đừng sử dụng phao hoặc nhân đôi.

Nếu bạn chắc chắn những thứ như một phần mười đồng xu sẽ không được tham gia thì chỉ cần lưu trữ đồng xu. Nếu bạn không thì hãy tìm ra đơn vị nhỏ nhất của loại tiền này sẽ là gì và sử dụng nó. Nếu bạn không thể, hãy sử dụng một cái gì đó như BigDecimal .

Giá trị ròng của tôi có thể sẽ luôn phù hợp với số nguyên 64 bit, nhưng những thứ như BigInteger hoạt động tốt cho các dự án lớn hơn thế. Chúng chỉ chậm hơn các loại bản địa.

Tìm hiểu làm thế nào để lưu trữ nó chỉ là một nửa vấn đề. Hãy nhớ rằng bạn cũng phải có thể hiển thị nó. Một thiết kế tốt sẽ tách hai điều này. Vấn đề thực sự với việc sử dụng phao ở đây là hai thứ đó được kết hợp với nhau.

nhập mô tả hình ảnh ở đây


6
Tôi thực sự không tìm kiếm một lời giải thích nào khác về lý do tại sao IEEE 754 không hoạt động vì tiền. Tôi đã đề cập trong OP rằng điều này đã được giải thích tốt ở nơi khác. Tương tự, có một lý do tôi sử dụng thuật ngữ "sử dụng vật lý". Cụ thể là vì trong khi giá xăng, giá trị trao đổi chứng khoán, v.v ... có thể có độ chính xác tùy ý, tiền thật (và số lượng lớn giao dịch người dùng) không đi qua hàng trăm nơi (và nhiều phần mềm khác nhau chỉ đại diện cho những gì có thể được thanh toán tiền vật chất). Một thông tin mà tôi đã tự hỏi là liệu tiền tệ tồn tại có đi vào vị trí thập phân hơn không.
Kat

3
"Sự kỳ lạ" của điểm nổi không chỉ giới hạn ở một nửa so với 1/10. Khía cạnh "điểm nổi" trong tên cũng gây ra kết quả không mong muốn.
whatsisname 17/03/2017

6
Trước khi số thập phân, tiền tệ của Anh là bảng Anh, shilling & pence, (£ sd), với £ 1 == 20s, 1s = 12d nên £ 1 = 240d nên 1d = 0,0046666666666 .. vì vậy thậm chí không thể được biểu thị dưới dạng thập phân. Trước khi gia nhập đồng euro, Lira của Ý đã đứng đầu 2346,4 (năm 2001) thành đô la Mỹ, do đó, những thứ như tiền lương và giá nhà đôi khi đạt đến giới hạn trên của phao chính xác duy nhất và các nhân vật kinh tế đã tăng gấp đôi.
Steve Barnes

2
Tôi chỉ tranh luận / chỉ ra rằng Tiền tệ là một thứ, và Giá là một thứ khác. Bạn có thể có độ chính xác hơn 0,01 đô la trong giá, nhưng bạn không thể trả một cách hiệu quả, với độ chính xác đó.
Machado

1
Ngoài ra, hình ảnh gia đình . Pft. :)
Machado

10

Tôi có thể tìm thấy nhiều câu hỏi về các thư viện để sử dụng để đại diện cho số tiền bằng một số loại tiền tệ.

"Thư viện" là không cần thiết trừ khi thư viện chuẩn của ngôn ngữ của bạn thiếu một số loại dữ liệu nhất định, như tôi sẽ giải thích.

Chắc chắn còn nhiều điều cần biết về tiền tệ trong sử dụng thế giới thực. Tôi đặc biệt quan tâm đến những gì bạn cần biết để thể hiện nó trong sử dụng vật lý (ví dụ: với đồng đô la, bạn không bao giờ có độ chính xác dưới 0,01 đô la, cho phép biểu diễn dưới dạng số nguyên xu).

Rất đơn giản, bạn không cần cố định dấu thập phân, không nổi dấu thập phân. Ví dụ, lớp BigDecimal của Java có thể được sử dụng để lưu trữ một lượng tiền tệ. Các ngôn ngữ hiện đại khác có các loại tương tự được tích hợp sẵn, bao gồm C #Python . Việc triển khai khác nhau, nhưng chúng thường lưu trữ một số dưới dạng một số nguyên, với vị trí thập phân là một thành viên dữ liệu riêng biệt. Điều này cho độ chính xác chính xác, ngay cả khi thực hiện số học sẽ đưa ra số dư lẻ (ví dụ: 0,0000001) với các số dấu phẩy động của IEEE.

Đặc biệt, những gì chúng ta cần biết để có thể lưu trữ giá trị bằng một số loại tiền và in ra?

Có một vài điểm quan trọng.

  1. Sử dụng một loại thập phân thực tế chứ không phải là dấu chấm động.

  2. Hiểu rằng một lượng tiền tệ có hai thành phần: giá trị (5,63) và mã hoặc loại tiền tệ (USD, CAD, GBP, EUR, et al). Đôi khi bạn có thể bỏ qua mã tiền tệ, lần khác nó rất quan trọng. Điều gì nếu bạn đang làm việc trên một hệ thống tài chính hoặc bán lẻ / thương mại điện tử cho phép nhiều loại tiền tệ? Điều gì xảy ra nếu bạn đang cố gắng lấy tiền từ một khách hàng bằng CAD, nhưng họ muốn thanh toán bằng MXN? Bạn cần loại "tiền" với mã tiền tệ và số tiền để có thể trộn các giá trị này (cũng là tỷ giá hối đoái, nhưng tôi không muốn đi quá xa vào một tiếp tuyến). Đồng thời, phần mềm tài chính cá nhân của tôi không bao giờ phải lo lắng về điều này vì mọi thứ đều bằng USD (nó có thể trộn lẫn các loại tiền tệ, nhưng tôi không bao giờ cần phải như vậy).

  3. Mặc dù một loại tiền tệ có thể có đơn vị vật lý nhỏ nhất trong thực tế (CAD và USD có xu, JPY chỉ là ... Yên), có thể có được nhỏ hơn. Câu trả lời của CandiedOrange chỉ ra giá nhiên liệu bằng một phần mười xu. Thuế tài sản của tôi được đánh giá là doanh nghiệp tính theo đô la, hoặc một phần mười của một xu (1/1000 đô la Mỹ). Đừng giới hạn bản thân ở mức 0,01 đô la. Mặc dù bạn có thể hiển thị các giá trị đó hầu hết thời gian, các loại của bạn sẽ cho phép nhỏ hơn (các loại thập phân được tham chiếu ở trên làm).

  4. Tính toán trung gian chắc chắn phải cho phép độ chính xác cao hơn một xu. Tôi đã làm việc trên các hệ thống bán lẻ / thương mại điện tử nơi các giá trị nội bộ được làm tròn thành $ 0,00000001 trong nội bộ. Độ chính xác vô hạn thường không được hỗ trợ bởi các loại thập phân (hoặc SQL), do đó phải có một số giới hạn. Ví dụ: chia 1/3 bằng BigDecimal của Java sẽ đưa ra một ngoại lệ mà không có RoundingMode hoặc MathContext được chỉ định vì giá trị không thể được biểu diễn chính xác.

    Dù sao, điều này là rất quan trọng trong một số trường hợp nhất định. Giả sử bạn có một người dùng có sáu mặt hàng trong giỏ hàng của anh ấy và anh ấy đi kiểm tra. Hệ thống của bạn phải tính thuế và làm như vậy cho mỗi mục vì các mục có thể bị đánh thuế khác nhau. Nếu bạn làm tròn thuế ở mỗi mặt hàng, bạn có thể gặp lỗi làm tròn số xu ở cấp độ giao dịch / giỏ hàng. Một cách tiếp cận để khắc phục điều này có thể là lưu trữ thuế đến nhiều vị trí thập phân hơn cho mỗi mục, lấy tổng số cho toàn bộ giao dịch và quay lại và làm tròn từng mục để tổng thuế là chính xác (có thể làm tròn một mục, giảm một mục khác).

Điều quan trọng cần nhận ra từ tất cả những điều này là một thứ quan trọng như đồng xu làm tròn có thể rất quan trọng đối với đúng người (ví dụ như một số khách hàng trước đây của tôi đã phải trả thuế bán hàng cho chính phủ thay cho khách hàng của họ). Tuy nhiên, đây đều là những vấn đề được giải quyết. Hãy ghi nhớ những điểm trên và tự mình thực hiện một số thử nghiệm, và bạn sẽ học bằng cách thực hiện.


Vào ngày 2, tôi nghĩ tỷ giá hối đoái là đủ để có được ít nhất là số của chính nó. Bạn phải xem xét rằng tỷ lệ thay đổi theo thời gian, có một vài cách xử lý khác nhau.
Izkata 17/03/2017

2
+1. Ngoài ra, tiền tệ thay đổi theo thời gian. Ở Brazil, chúng tôi đã nhiều lần thay đổi tiền tệ trong những năm 80 và 90, cắt giảm số không và đổi tên tiền khi cần thiết do lạm phát ngoài tầm kiểm soát. Điều đó có nghĩa là mọi khía cạnh của một loại tiền tệ có thể thay đổi theo thời gian.
Machado

@Izkata chắc chắn, tôi đã làm việc trên các hệ thống thay đổi tiền tệ. Tôi muốn chạm vào chủ đề này vì nó có liên quan. Tuy nhiên, đó không phải là trọng tâm của câu hỏi và tôi có thể có thể gõ một câu trả lời khác miễn là câu hỏi này về chủ đề trao đổi tiền tệ.

'"Thư viện" là không cần thiết trừ khi thư viện chuẩn của ngôn ngữ của bạn thiếu một số loại dữ liệu nhất định, như tôi sẽ giải thích.' Tiền tệ có thể có một nửa, phần tư, phần mười, phần tám, v.v., có nghĩa là chúng ta ít nhất cần một biểu diễn thập phân cho chúng. Nhưng chúng ta có hoàn toàn chắc chắn rằng không có loại tiền nào có tỷ lệ 1/3 không?
Daniel McLaury

4

Một nơi mà rất nhiều nhà phát triển phải đối mặt với một đại diện dữ liệu duy nhất cho bất kỳ loại tiền tệ nào là mua hàng trong ứng dụng cho các ứng dụng iOS. Khách hàng của bạn có thể được kết nối với một cửa hàng ở hầu hết mọi quốc gia trên thế giới. Và trong tình huống đó, bạn sẽ được cung cấp một giá mua bao gồm một số chính xác gấp đôi và mã tiền tệ.

Bạn cần lưu ý rằng những con số có thể lớn. Có những loại tiền mà tương đương với mười đô la là hơn 100.000 đơn vị. Và chúng tôi may mắn vì hiện tại không có loại tiền nào như đồng đô la Zimbabwe, nơi bạn có thể có hàng trăm nghìn tỷ tiền giấy!

Để hiển thị tiền tệ, bạn sẽ cần một số thư viện - bạn không có cơ hội để tự mình lấy nó. Màn hình phụ thuộc vào hai điều: Mã tiền tệ và ngôn ngữ của người dùng. Hãy nghĩ xem đô la Mỹ và đô la Canada sẽ được hiển thị như thế nào với một địa phương Hoa Kỳ và một địa phương Canada: Ở Hoa Kỳ, bạn có $ so với CAN $ và ở Canada bạn có US $ so với $. Hy vọng điều đó được tích hợp vào HĐH hoặc bạn có một thư viện tốt.

Đối với tính toán, mọi tính toán sẽ kết thúc bằng bước làm tròn. Bạn sẽ phải tìm ra cách bạn phải thực hiện việc làm tròn đó một cách hợp pháp . Đó không phải là vấn đề lập trình, đó là vấn đề pháp lý. Ví dụ: nếu bạn tính thuế VAT ở Vương quốc Anh, bạn phải tính thuế cho mỗi mặt hàng hoặc trên mỗi dòng mặt hàng và làm tròn nó xuống bằng đồng xu. Những gì bạn làm tròn để phụ thuộc vào tiền tệ. Nhưng các quy tắc rõ ràng phụ thuộc vào đất nước. Bạn không thể ngờ rằng một phép tính đúng về mặt pháp lý ở Anh sẽ đúng về mặt pháp lý ở Nhật Bản và ngược lại.


0

Đặc biệt, những gì chúng ta cần biết để có thể lưu trữ giá trị bằng một số loại tiền và in chúng ra?

  • "Để lưu trữ giá trị" : loại dữ liệu số điểm cố định và loại tiền tệ. Tôi nghĩ rằng đây là khá rõ ràng. Lưu trữ đến số điểm không cố định có thể liên quan đến một số làm tròn và thay đổi giá trị. Tính toán tiền tệ sẽ là một vấn đề khác nhau.
  • "Để in chúng ra" : ngôn ngữ người dùng. Nếu bạn may mắn, bạn có được thư viện chuẩn để làm mọi thứ, ví dụ như ký hiệu tiền tệ, dấu phân cách nghìn, dấu tách thập phân, độ chính xác, v.v.

Một số vấn đề ví dụ liên quan đến miền địa phương:

  • 100 USD theo miền địa phương Hoa Kỳ phải là 100 đô la, ở miền địa phương khác có dấu chấm là dấu phân cách thập phân sẽ là 100 đô la Mỹ.
  • Một số quốc gia sử dụng vô số thay vì hàng nghìn để nhóm số, ví dụ thay vì 10.000,00, đó chỉ là 1,0000,00
  • Vì lý do thực tế, mọi người không in tất cả các số cho các loại tiền tệ nhỏ, ví dụ thay vì 1.000.000.000,00 đô la, họ chỉ muốn bạn in 1 tỷ đô la.

Một vấn đề tiềm năng khác là ngay cả khi bạn lưu trữ tiền tệ chính xác theo số điểm cố định, có thể cần phải chuyển đổi thành số dấu phẩy động vì thư viện được sử dụng để in chỉ hỗ trợ dấu phẩy động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.