Tüm para birimleri için çalışan tek bir veri gösterimi var mı (Dolar, Euro ve Pound'dan farklı olanlar bile)?


12

Bir para biriminde miktarları temsil etmek için kullanılacak kütüphaneler hakkında birçok soru bulabilirim. Ve para birimini neden IEEE 754 kayan nokta numarası olarak saklamamanız gerektiğiyle ilgili eski sorun hakkında. Ama daha fazla bir şey bulamıyorum. Elbette gerçek dünya kullanımında para birimi hakkında daha fazla şey bilmek gerekir. Özellikle fiziksel kullanımda temsil etmek için bilmeniz gerekenlerle ilgileniyorum.

Ancak, bildiğiniz tek para birimi popüler batı para birimleri (dolar, euro ve pound gibi) olduğunda programınızın ne kadar çok yönlü olduğu konusunda varsayımlar yapmak zordur. Tamamen programlı bir perspektifle ilgili başka neler var? Dönüşüm konusuyla ilgilenmiyorum.

Özellikle, değerleri bir para biriminde saklayabilmemiz ve yazdırabilmemiz için ne bilmemiz gerekir?


2
Tüm programcılar para birimi miktarlarını manipüle eden endüstrilerde çalışmaz.
whatsisname

4
Oh elbette. Ancak bu hemen hemen her şey hakkında söylenebilir. Bu soruyu faydalı bulanların para ile çalışanlar olacağını varsayabiliriz.
Kat

5
NYC'deki bankalar ve diğer finansal hizmetler firmaları için birçok geliştirme çalışması yaptım. Ve sorunuza "kapalı form" cevabı olmadığını hemen hemen garanti ederim. Siz de "ne kadar matematik bilmek zorundayım?" Diye sorabilirsiniz. Örneğin, 1990'lı yıllarda hisse senedi fiyatları sekizinci ve 256'nın ondalık sayılarına geriledi ve çok fazla yeniden programlama gerektirdi. Bunun olacağını kim tahmin edebilirdi? Sadece uygulamalarınızın desteklediği işi ve bu işletme ihtiyaçlarını desteklemek için verilerin (bu durumda para biriminde) en iyi nasıl temsil edileceğini anlamalısınız.
John Forkosh

4
Benim 0.02: Fiyat bir şeydir. Para birimi başka.
Machado

3
Ben, Oh, tüm para birimleri için bazı ortak payda olmalı diye düşündüm. Ama belki de değil. Kuruş sterlini şu anda 1⁄100 pound, ancak 1⁄240 pound idi. Yani sadece 1/240'lık bir bölümünüz değil, aynı zamanda bir geçiş tarihiniz var ve muhtemelen eski pence için bir döviz kuru henüz açık değil. en.wikipedia.org/wiki/Penny_sterling Beni kovboy mermilerine bile başlama! en.wikipedia.org/wiki/Shell_money veya paranın gerçeğe dönüşmesi için inanç gerektirmesi gerçeği: en.wikipedia.org/wiki/Money StackExchange'e iyi uymasa bile harika bir soru!
GlenPeterson

Yanıtlar:


24

Örneğin, dolar ile, 0,01 $ 'dan daha düşük bir hassasiyetiniz olmaz

Gerçekten? resim açıklamasını buraya girin

para birimini neden IEEE 754 kayan nokta numarası olarak depolamamanız gerektiğiyle ilgili eski sorun.

resim açıklamasını buraya girin

Lütfen inçleri IEEE 754 kayan nokta numaralarında saklamaktan çekinmeyin . Tam olarak nasıl beklediğinizi depolarlar.

Lütfen cetveli bir inçlik kesimlere bölen keneleri kullanarak saklayabileceğiniz herhangi bir miktarda parayı IEEE 754 kayan nokta numaralarına depolamaktan çekinmeyin .

Neden? Çünkü IEEE 754'ü kullandığınızda bu şekilde saklıyorsunuz.

İnç ile ilgili olan şey yarıya bölünmüş olmalarıdır. Çoğu para birimi türüyle ilgili olan şey, onda birine bölünmüş olmasıdır (bazı türler odaklanmaz ancak odaklanalım).

Bu fark, çoğu programlama dili için, IEEE 754 kayan nokta numaralarına giriş ve çıkışların ondalık sayılarla ifade edilmesi dışında kafa karıştırıcı değildir ! Bu çok garip çünkü ondalık sayılarda saklanmıyorlar.

Bu nedenle , bilgisayardan saklamasını istediğinizde , bitlerin nasıl garip şeyler yaptığını asla göremezsiniz0.1 . Sadece ona karşı matematik yaptığınızda garipliği görüyorsunuz ve garip hataları var.

Gönderen Josh Bloch'un etkili java :

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

üretir 0.6100000000000001

Bu konuda en çok söylediklerimiz 1sağ tarafta oturan yol değil. Bunu elde etmek için kullanılması gereken tuhaf rakamlar. En popüler örneği kullanmak yerine 0.1, sorunu gösteren ve gizleyecek yuvarlamayı önleyen bir örnek kullanmalıyız.

Örneğin, bu neden işe yarıyor?

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

üretir -0.01

Çünkü şanslıyız.

Bazen "şanslı" olduğum için teşhis edilmesi zor problemlerden nefret ediyorum.

IEEE 754 0.1'i tam olarak depolayamaz. Ama eğer 0.1 saklamasını ve sonra yazdırmasını istersen 0.1 gösterecek ve her şeyin yolunda olduğunu düşüneceksin. İyi değil, ama göremiyorsunuz çünkü 0.1'e geri dönmek için yuvarlanıyor.

Bazı insanlar bu farklılıkları yuvarlama hatalarını çağırarak diğerlerinin kafasını karıştırır. Hayır, bunlar yuvarlama hataları değil. Yuvarlama, olması gerekeni yapıyor ve ondalık olmayanı ondalık sayıya dönüştürüyor, böylece ekranda yazdırabiliyor.

Ancak bu, sayının nasıl görüntüleneceği ve nasıl saklandığı arasındaki uyuşmazlığı gizler. Yuvarlama gerçekleştiğinde hata olmadı. Tam olarak depolayamayan bir sisteme bir sayı koymaya karar verdiğinizde ve tam olarak depolanmadığı zaman varsayıldığı zaman oldu.

Kimse π kesin bir hesap makinesinde saklamak için beklemiyor ve onunla iyi çalışmayı başarıyor. Yani sorun hassasiyetle ilgili değil. Beklenen hassasiyetle ilgilidir. Bilgisayarlar 0.1hesap makinemizin onda birini gösterir , bu nedenle hesap makinelerinin onda biri kadar mükemmel bir şekilde saklanmalarını bekleriz. Yapmazlar. Bu şaşırtıcı, çünkü bilgisayarlar daha pahalı.

Size uyuşmazlığı göstereyim:

resim açıklamasını buraya girin

1/2 ve 0.5'in mükemmel bir şekilde sıralandığına dikkat edin. Ancak 0.1 sıraya girmiyor. Tabii eğer 2'ye bölmeye devam ederseniz daha da yaklaşabilirsiniz ama asla tam olarak vurmayacaksınız. Ve her 2'ye bölüştüğümüzde daha fazla bite ihtiyacımız var. Yani, 2'ye bölen herhangi bir sistemle 0.1'i temsil etmek sonsuz sayıda bite ihtiyaç duyar. Sabit diskim o kadar büyük değil.

Böylece IEEE 754 , bitleri bittiğinde denemeyi durdurur. Hangi güzel çünkü aile fotoğrafları için sabit diskimde yer gerekir. Gerçekten değil. Aile fotoğrafları. : P

Her neyse, yazdıklarınız ve gördükleriniz ondalık sayılardır (sağda), ancak sakladığınız şey çifttir (solda). Bazen bunlar tamamen aynıdır. Bazen değiller. Bazen öyle olmadıklarında aynı gibi görünüyorlar. Yuvarlama bu.

Özellikle, değerleri bir para biriminde saklayabilmek ve yazdırabilmek için nelere ihtiyacımız var?

Lütfen, ondalık tabanlı paramı işliyorsanız şamandıra veya iki kat kullanmayın.

Onuncu kuruş gibi şeylerin dahil olmayacağından eminseniz, sadece kuruşları saklayın. O zaman bu para biriminin en küçük biriminin ne olacağını anlamaya çalışın ve bunu kullanın. Yapamıyorsanız , BigDecimal gibi bir şey kullanın .

Benim net değer muhtemelen her zaman iyi bir 64 bit tamsayı sığacak ama BigInteger gibi şeyler bundan daha büyük projeler için iyi çalışır. Yerli tiplerden daha yavaşlar.

Nasıl saklanacağını bulmak sorunun sadece yarısıdır. Bunu da görüntüleyebilmeniz gerektiğini unutmayın. İyi bir tasarım bu iki şeyi ayıracaktır. Burada şamandıra kullanmanın asıl sorunu, bu iki şeyin birbirine karışmasıdır.

resim açıklamasını buraya girin


6
Gerçekten IEEE 754'ün neden para için çalışmadığına dair başka bir açıklama aramıyordum. OP'de bunun başka yerlerde iyi açıklandığını söylemiştim. Benzer şekilde, "fiziksel kullanım" terimini kullanmamın bir nedeni var. Yani, gaz fiyatları, borsa değerleri, vb. fiziksel para). Merak ettiğim bir bilgi daha fazla ondalık yere giden para birimleri olup olmadığıydı.
Kat

3
Kayan noktanın "tuhaflığı" sadece 1 / 10'un yarısı ile sınırlı değildir. Addaki "kayan nokta" boyutu da bazen beklenmedik sonuçlara neden olur.
whatsisname

6
Ondalık ayırmadan önce İngiltere para birimi pound, şilin ve pence (£ sd) idi, £ 1 == 20s, 1s = 12d yani 1 £ = 240d yani 1d = 0.0046666666666 .. ondalık olarak bile temsil edilemedi. Euro'ya katılmadan önce, İtalyan Lirası 2346,4'ü (2001'de) ABD $ 'a yükseltti, böylece maaşlar ve konut fiyatları gibi şeyler bazen tek hassas şamandıraların üst sınırına ulaştı ve ekonomik rakamlar iki katın üst seviyelerine çarptı.
Steve Barnes

2
Para biriminin bir şey olduğunu ve Fiyatın başka bir şey olduğunu iddia ediyorum / işaret ediyorum. Fiyatlarda 0,01 dolardan fazla hassasiyete sahip olabilirsiniz, ancak bu hassasiyetle etkili bir şekilde ödeme yapamazsınız.
Machado

1
Ayrıca, aile fotoğrafları . Pft. :)
Machado

10

Bir para biriminde miktarları temsil etmek için kullanılacak kütüphaneler hakkında birçok soru bulabilirim.

Açıklayacağım gibi, dilinizin standart kütüphanesinde belirli veri türlerinde eksik olmadıkça "Kütüphaneler" gereksizdir.

Elbette gerçek dünya kullanımında para birimi hakkında daha fazla şey bilmek gerekir. Özellikle fiziksel kullanımda temsil etmek için bilmeniz gerekenlerle ilgileniyorum.

Oldukça basit, sabit nokta ondalık gerekir , kayan nokta ondalık değil . Örneğin, Java'nın BigDecimal sınıfı bir para birimi tutarını saklamak için kullanılabilir. Diğer modern diller, C # ve Python dahil olmak üzere benzer türlere sahiptir . Uygulamalar değişir, ancak genellikle bir sayıyı tamsayı olarak saklarlar ve ondalık konum ayrı bir veri üyesi olarak saklarlar. Bu, IEEE kayan nokta sayıları ile garip kalıntılar (örn. 0.0000001) verecek aritmetik yaparken bile kesin bir hassasiyet verir.

Özellikle, değerleri bir para biriminde saklayabilmek ve yazdırabilmek için nelere ihtiyacımız var?

Birkaç önemli nokta var.

  1. Kayan nokta yerine gerçek ondalık türü kullanın.

  2. Bir para birimi tutarının iki bileşeni olduğunu anlayın: bir değer (5.63) ve bir para birimi kodu veya türü (USD, CAD, GBP, EUR ve diğerleri). Bazen para birimi kodunu göz ardı edebilirsiniz, diğer zamanlarda hayati önem taşır. Birden fazla para birimine izin veren bir finansal veya perakende / e-ticaret sistemi üzerinde çalışıyorsanız? CAD'deki bir müşteriden para almaya çalışıyorsanız, ancak MXN ile ödeme yapmak istiyorlarsa ne olur? Bu değerleri karıştırmak için bir para birimi kodu ve para birimi miktarı ile bir "para" türü gerekir (aynı zamanda döviz kuru, ama bir teğet çok fazla almak istemiyorum). Her şey (o USD olduğu için aynı zamanda, benim kişisel finans yazılımı bu konuda endişe gerekiyor asla olabilir para karıştırmak, ama gerek asla).

  3. Bir para birimi pratikte en küçük fiziksel birime sahip olsa da (CAD ve USD'nin sentleri vardır, JPY sadece ... Yen'dir) küçülmek mümkündür. CandiedOrange'in cevabı, bir sentin onda biri cinsinden yakıt fiyatlarını gösteriyor. Emlak vergilerim dolar başına değirmen veya yüzde onda biri (ABD Doları'nın 1 / 1000'i) olarak değerlendirilir. Kendinizi 0,01 $ ile sınırlamayın. Bu değerleri çoğu zaman görüntülemenize rağmen , türleriniz daha küçük olmasına izin vermelidir (yukarıda belirtilen ondalık türler buna izin verir).

  4. Ara hesaplamalar kesinlikle tek bir kuruştan daha fazla hassasiyete izin vermelidir. Dahili değerlerin dahili olarak 0.00000001 dolara yuvarlandığı perakende / e-ticaret sistemlerinde çalıştım. Sonsuz hassasiyet genellikle ondalık türler (veya SQL) tarafından desteklenmez, bu nedenle bir miktar sınırlama olması gerekir . Örneğin, Java'nın BigDecimal'ini kullanarak 1/3 bölmek, değer tam olarak temsil edilemediğinden bir RoundingMode veya MathContext belirtilmemiş bir istisna atar.

    Her neyse, bu bazı durumlarda kritiktir. Alışveriş sepetinde altı öğe bulunan bir kullanıcınız olduğunu varsayalım ve kontrol etmeye gider. Sisteminizin vergiyi hesaplaması gerekir ve öğeler farklı şekilde vergilendirilebileceğinden öğe başına yapar. Her öğedeki vergileri yuvarlarsanız, işlem / alışveriş sepeti düzeyinde kuruş yuvarlama hataları alabilirsiniz. Bunu düzeltmek için bir yaklaşım, vergileri öğe başına daha fazla ondalık basamağa depolamak, tüm işlem için toplamı almak ve her bir öğeye geri dönüp yuvarlamak olabilir, böylece toplam vergi doğrudur (belki bir öğe yukarı, diğeri aşağı yuvarlanır).

Tüm bunların farkına varılması gereken önemli şey, yuvarlama pennies kadar önemli bir şeyin doğru insanlar için çok önemli olabileceğidir (örneğin, devlet satış vergilerini müşterileri adına ödemek zorunda kalan bazı geçmiş müşterilerim). Ancak, bunların hepsi çözülmüş problemlerdir. Yukarıdaki noktaları aklınızda bulundurun ve kendi başınıza bazı deneyler yapın ve yaparak öğreneceksiniz.


2'de, döviz kurunun en azından kendi numarasını elde etmek için yeterli olduğunu düşünüyorum. Oranların zaman içinde değiştiğini düşünmelisiniz, bu da birkaç farklı kullanım şekline sahiptir.
Izkata

2
+1. Ayrıca, para birimleri zamanla değişir. Brezilya'da 80'lerin ve 90'ların üzerinde defalarca döviz değişiklikleri yaptık, kontrol dışı enflasyon nedeniyle sıfırları kesti ve gerektiğinde para birimini yeniden adlandırdık. Bu, bir para biriminin her yönünün zaman içinde değişebileceği anlamına gelir.
Machado

@Izkata kesinlikle para birimlerini değiştiren sistemler üzerinde çalıştım. Konuyla alakalı olduğu için konuya değinmek istedim. Ancak, bu sorunun odak noktası değildir ve muhtemelen bu para alışverişi konusunda bir cevap yazabilirim.

Açıklayacağım gibi, dilinizin standart kütüphanesinde belirli veri türlerinde eksik olmadıkça "Kütüphaneler" gerekli değildir. ' Para birimlerinin yarısı, çeyrekleri, onda biri, sekizinci, vb. Olabilir, bu da en azından onlar için ondalık bir temsile ihtiyacımız olduğu anlamına gelir. Ama 1/3'lük bir parçaya sahip para biriminin olmadığından tamamen emin miyiz?
Daniel McLaury

4

Birçok geliştiricinin herhangi bir para birimi için tek bir veri temsiliyle karşılaştığı bir yer, iOS uygulamaları için uygulama içi satın alımlar içindir. Müşteriniz dünyanın hemen hemen her ülkesindeki bir mağazaya bağlanabilir. Ve bu durumda, çift ​​kesinlikli bir sayı ve bir para birimi kodundan oluşan bir satın alma fiyatı verilecektir .

Sayıların büyük olabileceğinin farkında olmalısınız. On dolar eşdeğerinin 100.000 birimden fazla olduğu para birimleri vardır. Şu anda, yüz trilyon banknot alabileceğiniz Zimbabwe doları gibi para birimleri olmadığı için şanslıyız!

Para birimlerini görüntülemek için bir kütüphaneye ihtiyacınız olacak - hepsini kendiniz elde etme şansınız yok. Ekran iki şeye bağlıdır: Para birimi kodu ve kullanıcının yerel ayarı. ABD doları ve Kanada Doları'nın ABD yerel ayarıyla ve Kanada yerel ayarıyla nasıl görüntüleneceğini düşünün: ABD'de CAN $ ile CAN $ ve Kanada'da ABD Doları ile $ ABD Doları arasındasınız. Umarım bu işletim sisteminde yerleşiktir, ya da iyi bir kütüphaneniz var.

Hesaplamalar için, herhangi bir hesaplama yuvarlama adımı ile sona erecektir. Bu yuvarlamayı yasal olarak nasıl yapmanız gerektiğini öğrenmeniz gerekecek . Bu bir programlama problemi değil, yasal bir problem. Örneğin, İngiltere'de KDV hesaplarsanız, kalem başına veya kalem başına vergi hesaplamanız ve kuruşları yuvarlamak zorundasınız. Ne yuvarladığınız para birimine bağlıdır. Ancak kurallar açıkça ülkeye bağlı. İngiltere'de yasal olarak doğru olan bir hesaplamanın Japonya'da yasal olarak doğru olacağını ve tam tersini bekleyemezsiniz.


0

Özellikle, değerleri bir para biriminde saklayabilmemiz ve yazdırabilmemiz için ne bilmemiz gerekir?

  • "değerleri saklamak için" : sabit noktalı bir veri türü ve bir para birimi türü. Bence bunlar çok açık. Sabit olmayan bir sayıya kaydetmek, bazı yuvarlamaları içerebilir ve değeri değiştirebilir. Para birimi hesaplaması farklı bir sorun olacaktır.
  • msgstr "bunları yazdırmak için" : kullanıcı yerel ayarı. Şanslıysanız, her şeyi yapmak için standart kitaplığa sahip olursunuz, örneğin para birimi simgesi, bin ayırıcı, ondalık ayırıcı, hassasiyet vb.

Yerel ayarlarla ilgili bazı örnek sorunlar:

  • ABD yerel ayarında 100 USD 100,00 $, ondalık ayırıcı olarak nokta olan diğer yerel ayarlarda 100,00 $ olmalıdır.
  • Bazı ülkeler sayıları gruplamak için bin yerine sayısız kullanırlar, örneğin 10.000.00 yerine sadece 1.0000.00
  • Pratik nedenlerle, insanlar tüm sayıları küçük para birimleri için yazdırmazlar, örneğin 1.000.000.000,00 dolar yerine, sadece 1 milyar dolar yazdırmanızı istiyorlar.

Başka bir olası sorun, para birimini sabit nokta numarasında doğru bir şekilde saklasanız bile, yazdırmak için kullanılan kütüphane yalnızca kayan noktayı desteklediğinden kayan nokta numarasına dönüştürülmesi gerekebilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.