Oyun içi para birimi için hangi veri türünü kullanmalıyım?


96

Basit bir iş simülasyon oyununda (Java + Slick2D'de yerleşik olarak), bir oyuncunun şu anki parası bir floatveya bir intveya başka bir şey olarak mı depolanmalı ?

Kullanım durumumda işlemlerin çoğu sent (0,50 $, 1,20 $, vb.) Kullanacak ve basit faiz oranı hesaplamaları uygulanacaktır.

Asla floatpara için kullanmaman gerektiğini söyleyenlerin yanı sıra, asla para için kullanmaman gerektiğini söyleyenleri gördüm int. intGerekli yüzdelik hesaplamaları kullanmam ve yuvarlamam gerektiğini hissediyorum . Ne kullanmalıyım?


2
Bu soru StackOverflow'ta tartışıldı. BigDecimal gibi gözüküyor muhtemelen. stackoverflow.com/questions/285680/…
Ade Miller

2
Java Currency, kayan noktaya özgü hassasiyet problemleri olmadan size ondalık matematik vermek için ölçeklendirilmiş sabit nokta matematiğini kullanan Delphi's gibi bir tipe sahip değil mi?
Mason Wheeler

1
Bu oyun. Muhasebe yuvarlatılmış bir kuruş için sizi linç etmeyecek ve bu nedenle para birimi için kayan nokta kullanmaya karşı normal sebepler önemli değil.
Loren Pechtel

@MasonWheeler: Java BigDecimalbu tür problemler için var.
Martin Schröder

Yanıtlar:


92

Kullanabilir intve sent içindeki her şeyi düşünebilirsiniz. 1,20 $ sadece 120 sent. Ekranda, ondalık işareti ait olduğu yere koyuyorsunuz.

Faiz hesaplamaları sadece kesilir veya tamamlanır. Yani

newAmt = round( 120 cents * 1.04 ) = round( 124.8 ) = 125 cents

Bu şekilde, her zaman etrafta sadık kalarak dağınık ondalık sayılarınız olmaz. Hesabınıza para yatırılmayacak kadar para toplayarak zengin olabilirsiniz.


3
Eğer kullanırsanız roundiçin aşağı atmak için gerçek neden yoktur int, var mı?
sam hocevar,

19
+1. Kayan nokta sayıları eşitlik karşılaştırmalarını artırır, düzgün biçimlendirmeleri daha zor ve zamanla komik yuvarlama hataları ortaya çıkarırlar. Bunları kendin yapmak daha iyidir, böylece daha sonra şikayet edemezsin. Gerçekten çok fazla iş değil.
Dobes Vandermeer,

+1. Oyunuma gitmek için iyi bir yol gibi görünüyor. Girişleri kendim yuvarlayacağım ve tüm yüzdürme problemlerinden uzak duracağım.
Lucas Tulio

Sadece bir feragatname: Bu cevabın doğru cevabını değiştirdim, çünkü kullandım. Çok basit ve böyle basit bir oyun bağlamında, sayılmamış ondalık sayıları gerçekten önemli değil.
Lucas Tulio

3
Ancak, 100 yerine 10,000 faktörü olan 100 Temel Puan = 1 cent olan Temel Puanları kullanın. Bu, tüm Finansal, Bankacılık veya Muhasebe uygulamaları için GAAP tarafından istenir.
Pieter Geerkens

66

Tamam, içeri atlayacağım.

Benim tavsiyem: bu bir oyun. Sakin ol ve kullan double.

İşte benim mantığım:

  • floatMilyonlara birim eklerken ortaya çıkan hassas bir sorunu var, bu yüzden iyi huylu olsa da, bu tipten kaçınırdım. doublesadece quintilloların etrafında bir problem yaşamaya başlar (bir milyar milyar).
  • Eğer faiz oranlarını sahip olacak olduğundan, zaten teorik sonsuz hassasiyet gerekir:% 4 faiz oranları ile, 100 $ daha sonra $ 104, $ 108,16, daha sonra $ 112,4864, bu yapar vs. olacak intve longnerede ile durdurmak için bilmiyorum çünkü yararsız ondalık sayılar.
  • BigDecimalSize keyfi bir hassasiyet verir, ancak hassasiyeti bir süre sıkmadığınız sürece acı verici bir şekilde yavaşlar. Yuvarlama kuralları nelerdir? Nerede duracağını nasıl seçersin? Bundan daha hassas bitlere sahip olmak değer doublemidir? Inanmıyorum.

Finansal uygulamalarda sabit nokta aritmetik kullanılmasının nedeni deterministik olmalarıdır. Yuvarlama kuralları, bazen yasalarla mükemmel bir şekilde tanımlanmıştır ve kesinlikle uygulanmalıdır, ancak yuvarlama yine de bir noktada gerçekleşir. Kesinlik esas alınarak verilen bir tür lehine herhangi bir argüman sahte olabilir. Tüm tiplerde yapacağınız hesaplama türleriyle ilgili hassas sorunlar vardır.

Pratik örnekler

Kabul etmediğim yuvarlama ve kesinlik hakkında bir şeyler iddia eden epeyce yorum görüyorum. İşte ne demek istediğimi açıklamak için birkaç ek örnek.

Depolama : Baz üniteniz yüzde ise, değerleri saklarken büyük olasılıkla en yakın yüzde ye yuvarlamak istersiniz:

void SetValue(double v) { m_value = round(v * 100.0) / 100.0; }

Bir tamsayı türü ile sahip olamayacağınız bu yöntemi benimsediğinizde kesinlikle hiçbir yuvarlama sorunu yaşamayacaksınız.

Alma : tüm hesaplamalar doğrudan çift değerler üzerinden yapılabilir, dönüşüm yapılmaz:

double value = data.GetValue();
value = value / 3.0 * 12.0;
[...]
data.SetValue(value);

Eğer değiştirirseniz Yukarıdaki kod çalışmaz unutmayın doubleile int64_t: bir örtük dönüştürme olacak double, daha sonra kesme için int64_tinformation.data.GetValue olası bir kaybıyla, ()

Karşılaştırma : Karşılaştırmalar kayan nokta tiplerinde doğru olanı oluşturur. Bunun gibi bir karşılaştırma yöntemi kullanmanızı öneririm:

/* Are values equal to a tenth of a cent? */
bool AreCurrencyValuesEqual(double a, double b) { return abs(a - b) < 0.001; }

Yuvarlama adaleti

Hesapta% 4'lük faiz oranla 9,99 YTL olduğunu varsayalım. Oyuncu ne kadar kazanmalı? Tam sayı yuvarlama ile $ 0.03; kayan nokta yuvarlama ile 0,04 dolar alırsınız. İkincisinin daha adil olduğuna inanıyorum.


4
+1. Eklemek istediğim tek açıklama, mali uygulamaların belirli önceden tanımlanmış gereksinimlere uyduğu gibi, yuvarlama algoritması da öyle. Oyun bir kumarhane ise, benzer standartlara uygundur ve ardından çift bir seçenek değildir.
Ivaylo Slavov

2
Kullanıcı arayüzünü biçimlendirmek için yuvarlama kuralları hakkında düşünmeniz gerekir. Çünkü her zaman bir oyunu elektronik tablo olarak görmeye çalışacak oyuncuların bir kısmı vardır, eğer arka uçunuzu çığlık atlayan insanlarla uğraşmak istemiyorsanız, arka uçunuzu UI'nızla aynı hassasiyeti kullanmaz. 'yanlış' sonuçların sessiz kalması için en iyi seçeneğin gösterilmesi, aynı iç ve dış gösterimi kullanmaktır; bu, sabit bir nokta formatı kullanmak anlamına gelir. Performans sorunu olmazsa, BigDecimal bunu yapmak için en iyi seçimdir.
Dan Ne

10
Bu cevaba katılmıyorum. Yuvarlama sorunları ortaya çıkıyor ve düşerse ve ek bir yuvarlama kullanmıyorsanız, 1,00 ABD doları aniden 0,99 ABD doları olabilir. Fakat en önemlisi, keyfi kesinlik ondalık değerlerinin yavaş olması (neredeyse) tamamen alakasızdır. Neredeyse 2013'deyiz ve binlerce rakamla büyük faktörizasyonlar, trig nesneler veya logaritmalar yapmazsanız, binlerce basamağa sahipseniz, performansta bir diş bile farketmeyeceksiniz. Her neyse, basit her zaman en iyisidir, bu yüzden tavsiyem tüm sayıları sent olarak saklamak. Bu şekilde hepsi int_64ts.
Panda Pajama

8
@Sam banka hesabımı en son kontrol ettiğimde, bakiyem .0000000000000001’de bitmedi. Gerçek para birimi sistemleri bölünemez birimlerle çalışmalıdır ve bu tamsayılarla doğru şekilde temsil edilir. Para birimlerini doğru bir şekilde yapmanız gerekiyorsa (ki bunlar gerçek finansal dünyada pek de yaygın değildir), bunları yapmak zorundasınız, böylece para kaybedilmez. Örneğin 10/3 = 3+3+4veya 10/3 = 3+3+3 (+1). Diğer tüm işlemler için, tamsayılar, herhangi bir işlemde yuvarlaklama problemleri yaratabilecek kayan noktadan farklı olarak mükemmel çalışır.
Panda Pajama

2
@SamHocevar 999 * 4/100. Düzenleme ile öngörülmediği takdirde, tüm yuvarlamaların banka lehine yapılacağını varsayınız.
Dan Neely,

21

Java ( float, double) ' daki kayan nokta türleri, temel nedenlerden dolayı para birimleri için iyi bir temsil değildir - yuvarlamada bir makine hatası vardır. Basit bir hesaplama tam sayı döndürür bile - gibi 12.0/2(6.0), kayan nokta olabilir yanlış (nedeniyle bellekte bu tür spesifik temsil tho) o kadar yuvarlak 6.0000000000001veya 5.999999999999998veya benzer. Bu, işlemcide oluşan belirli bir makine yuvarlamasının bir sonucudur ve onu hesaplayan bilgisayara özgüdür. Genellikle, bu değerler ile çalışmak nadiren sorun olur, çünkü hata oldukça ihmal edicidir, ancak bunu kullanıcıya göstermek acı vericidir.

Bunun olası bir çözümü, gibi kayar nokta veri türünde özel bir uygulama kullanmaktır BigDecimal. En azından yuvarlama hatalarını makineye özgü olmayacak şekilde izole eden, ancak performans açısından daha yavaş olan daha iyi hesaplama mekanizmalarını destekler.

Yüksek üretkenliğe ihtiyacınız varsa, basit tiplere daha iyi uyursunuz. Eğer birlikte çalışmak önemli finansal veriler ve her kuruş sonra kullanmak tavsiye ederim (bir Forex uygulaması veya bazı kumarhane oyunu gibi) önemlidir Longya long. LongBüyük miktarlarda ve iyi hassasiyet işlemek için izin verir. İhtiyacınız varsayalım ki, ondalık basamağın 4 basamağından 4 basamak sonra, tek ihtiyacınız olan miktar 10000 ile çarpmaktır. Çevrimiçi casino oyunları geliştirme konusunda deneyim sahibi olduğumda, Longsık sık parayı sent olarak göstermek için kullanıldığını gördüm . . Forex uygulamalarında hassasiyet daha önemlidir, bu yüzden daha büyük bir çarpana ihtiyacınız olacaktır - yine de, tam sayılarda makine yuvarlama sorunları yoktur (elbette 3/2'deki gibi manuel yuvarlama kendiniz yapmalısınız).

Kabul edilebilir bir seçenek, standart kayan nokta türlerini kullanmak olacaktır - Floatve Doubleperformans yüzdelik yüzdelere kadar doğruluktan daha önemliyse. Ardından, ekran mantığınızda, ihtiyacınız olan tek şey önceden tanımlanmış bir format kullanmaktır , böylece potansiyel makine yuvarlamasının çirkinliği kullanıcıya ulaşmaz.


4
+1 Bir detay: "İhtiyacınız olduğunu varsayalım, diyelim, ondalık basamağından sonra 4 hane, tek ihtiyacınız olan miktarı 1000 ile çarpmak." -> Buna sabit nokta denir.
Laurent Couvidou

1
@Sam, sayılar örnek kazık için verildi. Yine de, şahsen böyle basit sayılarla garip sonuçlar gördüm, ancak bu sık sık bir senaryo değil. Kayan noktalar oynamaya geldiğinde, bu muhtemelen daha muhtemeldir, fakat daha fazla fark etmesi muhtemel değildir
Ivaylo Slavov

2
@Ivaylo Slavov, sana katılıyorum. Cevabımda sadece fikrimi yaptım. Tartışmayı ve doğru şeyi yapmaya istekli olmayı seviyorum. Ayrıca fikriniz için teşekkürler. :)
Md Mahbubur Rahman

1
@SamHocevar: Bu akıl yürütme her durumda işe yaramaz. Bakınız: ideone.com/nI2ZOK
Samaursa

1
@SamHocevar: Bu da garanti değil. Aralıktaki tam sayıdaki sayılar ilk bölümde hata biriktirmeye başlar: ideone.com/AKbR7i
Samaursa

17

İçin küçük ölçekli oyun ve nerede süreç hızı, bellek, orada (Hassasiyetle veya matematik eş işlemcisi ile çalışmak acı yavaş yapabilir kadar) önemli bir konudur çift yeterlidir.

Ancak büyük ölçekli oyunlar için (örneğin, sosyal oyunlar) ve işlem hızının, hafızanın sınırlı olmadığı yerlerde, BigDecimal daha iyidir. Çünkü burada

  • parasal hesaplamalar için int veya uzun.
  • yüzer ve çiftler, temel 10 gerçek sayının çoğunu doğru bir şekilde gösteremez.

Kaynaklar:

Gönderen https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency

Çünkü yüzdürme ve ikiye katlanma, çoğu 10 temel sayının tamamını temsil edemez.

Bu bir IEEE-754 kayan nokta sayısının nasıl çalıştığını gösterir: işaret için bir bit, bir üs için bir kaç bit ve gerçek kesir için kalan kısım. Bu, sayıların 1.45 * 10 ^ 4'e benzer bir şekilde temsil edilmesine yol açar; üssü 10 olmak yerine, iki.

Tüm gerçek ondalık sayılar, aslında, on gücünün kesin kesirleri olarak görülebilir. Örneğin, 10.45 gerçekten 1045/10 ^ 2'dir. Ve bazı kesirler tam olarak 10'luk bir gücün (1 / 3'ü akla geliyor) bir kesriyle temsil edilemezken, bazıları tam olarak ikinin de bir gücünün kesri olarak temsil edilemez. Basit bir örnek olarak, kayan nokta değişkeni içinde 0,1'i depolayamazsınız. 0.099999999999999999996 gibi bir değer olan en yakın gösterilebilir değeri elde edersiniz ve yazılım görüntülendiğinde değeri 0,1'e yuvarlar.

Ancak, doğru olmayan sayılar üzerinde daha fazla toplama, çıkarma, çarpma ve bölme işlemleri gerçekleştirirken, küçük hatalar arttıkça daha fazla hassasiyet kaybedersiniz. Bu, mükemmel doğruluğun gerektiği yerlerde yüzer ve parayla başa çıkmak için yetersiz kalıyor.

Bloch, J., Etkin Java, 2. Baskı, Öğe 48:

The float and double types are particularly ill-suited for 

Parasal hesaplamalar, bir şamandıra veya tam olarak iki katı olarak 0.1 (veya on diğer herhangi bir negatif gücü) temsil etmek mümkün olmadığından dolayı.

For example, suppose you have $1.03 and you spend 42c. How much money do you have left?

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

prints out 0.6100000000000001.

The right way to solve this problem is to use BigDecimal, 

parasal hesaplamalar için int veya uzun.

Ayrıca bir göz atın


Ben sadece küçük hesaplamalar için uygun olan kısmı kabul etmiyorum. Gerçek hayat deneyimlerime göre, iyi hassasiyet ve büyük miktarda parayla başa çıkabilecek kadar kanıtlanmış oldu. Evet, kullanımı biraz hantal olabilir ancak BigDecimal'i iki önemli noktada yener - 1) daha hızlıdır (BigDecimal, yerleşik yuvarlama / çift olarak kullanılan CPU yuvarlamasında kullanılan yöntemle yavaşlayan yazılım yuvarlamasını kullanır) ve 2) BigDecimal kesinliği kaybetmeden bir veritabanında devam etmek daha zordur - tüm veritabanları bu tür 'özel' türlerini desteklemez. Long, tüm büyük veritabanlarında iyi bilinir ve yaygın olarak desteklenir.
Ivaylo Slavov

@Ivaylo Slavov, Benim hatam için özür dilerim. Cevabımı güncelledim.
Md Mahbubur Rahman,

Aynı sorun için farklı bir yaklaşım sunmak için özür dilemenize gerek yok :)
Ivaylo Slavov

2
@Ivaylo Slavov, sana katılıyorum. Cevabımda sadece fikrimi yaptım. Tartışmayı ve doğru şeyi yapmaya istekli olmayı seviyorum. Ayrıca fikriniz için teşekkürler. :)
Md Mahbubur Rahman,

Bu sitenin amacı sorunları netleştirmek ve OP'nin özel senaryoya bağlı olarak doğru kararı vermesine yardımcı olmaktır. Yapabileceğimiz tek şey süreci hızlandırmaya yardımcı olmak :)
Ivaylo Slavov

13

Sen istiyoruz saklamak da para longve hesaplamak da para doubleen az bir yedek olarak. Tüm işlemlerin olarak yapılmasını istiyorsunuz long.

Para birimini saklamak istemenizin nedeni, para birimini longkaybetmek istememenizdir.

Diyelim ki a kullanıyorsunuz doubleve paranız yok. Birisi size üç dimes verir ve sonra onları geri alır.

You:       0.1+0.1+0.1-0.1-0.1-0.1 = 2.7755575615628914E-17

Bu hiç hoş değil. Belki de 10 doları olan biri, ilk önce size üç dim vererek ve ardından başkalarına 9,70 dolar vererek servetini vermek ister.

Them: 10.0-0.1-0.1-0.1-9.7 = 1.7763568394002505E-15

Sonra onlara dimeleri geri veriyorsun:

Them: ...+0.1+0.1+0.1 = 0.3000000000000018

Bu daha yeni bozuldu.

Şimdi, uzun süre kullanalım, onuncu sentin izini sürelim (yani 1 = 0,001 $). Herkese gezegende bir milyar, yüz on iki milyon, yetmiş beş bin, yüz kırk üç dolar verelim:

Us: 7000000000L*1112075143000L = 1 894 569 218 048

Bekle, herkese bir milyar dolardan fazla verebiliriz ve sadece ikiden biraz fazla harcayabiliriz. Taşma burada bir felakettir.

Yani, bir miktar parayı hesaplayarak konum zaman transfer etmek, kullanım doubleve Math.roundo almak long. Sonra kullanarak bakiyeleri düzeltin (her iki hesabı da ekleyin ve çıkarın) long.

Ekonominiz sızmayacak ve katrilyon dolara yükselecek.

Daha zor meseleler var - örneğin, yirmi ödeme yaparsanız ne yaparsınız? * - ama bu başlamanız gerekir.

* Bir ödemenin ne kadar olduğunu hesaplarsınız long; daha sonra çarpınız 20.0ve menzilde olup olmadığını kontrol ediniz; öyleyse, 20Lbakiyenizden düşülen tutarı almak için ödemeyi çarpın . Genel olarak, tüm işlemlerin şu şekilde yapılması gerekir; longbu nedenle , tüm işlemleri tek tek toplamanız gerekir; kısayol olarak çoğaltabilirsiniz, ancak yuvarlama hataları eklemediğinizden ve taşmadığınızdan emin olmanız gerekir; doublebu, gerçek hesaplamayı yapmadan önce kontrol etmeniz gereken anlamına gelir long.


8

Kullanıcıya gösterilebilecek herhangi bir değerin neredeyse her zaman bir tamsayı olması gerektiğini söylemeye kadar giderim. Para, bunun yalnızca en belirgin örneğidir. 900 HP ile bir canavara 225 kez hasar vermek ve hala 1 tane HP kaldığını bulmak, bir pennyin görünmeyen bir kuruşunun görünmez bir kısmını bulduğunuzu hissetmek kadar deneyimlerden de kopacaktır.

Daha teknik kısımda, birinin ilgi çekici gibi gelişmiş şeyler yapmak için yüzmeye geri dönmesi gerekmediğine dikkat çekmek gerekiyor. Seçtiğiniz tamsayıda yeterince boşluk bırakmadığınız sürece, bir çarpma yazın ve bir bölme, örneğin% 4'lük bir yuvarlama eklemek için ondalık sayı ile çarpma için geçerli olacaktır:

number=(number*104)/100

Standart kurallara uygun olarak% 4 eklemek için:

number=(number*104+50)/100

Burada kayan nokta yanlışlığı yok, yuvarlama her zaman tam olarak .5işaretin üzerinde kalıyor.

Düzenleme, asıl soru:

Tartışma Ben soru her ne özetleyen yaklaşık basit daha yararlı olabileceğini düşünmeye başlar getirmede ne gören int/ floatcevap. Sorunun özünde veri tipleri ile ilgili değil, programın ayrıntılarını kontrol altına almakla ilgili.

Tamsayı olmayan bir değeri temsil etmek için bir tamsayı kullanmak programlayıcıyı uygulama ayrıntılarıyla uğraşmaya zorlar. "Hangi hassasiyeti kullanmalı?" ve "Yuvarlamanın yolu nedir?" açıkça cevaplanması gereken sorulardır.

Diğer taraftan, bir şamandıra programcıyı endişelenmeye zorlamaz, zaten ne olacağını umuyor. Ancak bir şamandıra sonsuz bir hassasiyet olmadığından, bazı yuvarlamalar gerçekleşecek ve bu yuvarlama oldukça tahmin edilemez.

Tek kullanımda ne olur yüzer ve yuvarlama kontrolünü almak ister misiniz? Neredeyse imkansız olduğu ortaya çıkıyor. Şamandırayı gerçekten tahmin edilebilir kılmanın tek yolu, sadece bütünüyle temsil edilebilecek değerleri kullanmaktır 2^n. Ancak bu yapı yüzmeyi oldukça zorlaştırıyor.

Böylece basit sorunun cevabı şudur: Eğer kontrolü ele almak istiyorsanız, tamsayıları kullanın, değilse, yüzer alanları kullanın.

Ancak tartışılmakta olan soru, sorunun başka bir şeklidir: Kontrolü ele almak ister misiniz?


5

"Sadece bir oyun" olsa bile , çok uzun zaman önce desteklenen Martin Fowler'tan Money Pattern'i kullanırdım .

Neden?

Yerelleştirme (L10n): Bu deseni kullanarak oyun para biriminizi kolayca yerelleştirebilirsiniz. "Transport Tycoon" gibi eski tycoon oyunlarını düşünün. Oyuncunun oyun içi para birimini (yani İngiliz Sterlini'nden Amerikan Doları'na kadar) gerçek dünya para birimini karşılaması için kolayca değiştirmelerine izin verir.

Ve

Uzun veri türü 64 bit işaretli ikisinin tamamlayıcı tamsayısıdır. Minimum -9,223,372,036,854,775,808 değerine ve maksimum 9,223,372,036,854,775,807 (dahil) değerine sahiptir ( Java Tutorials )

Bu, mevcut M2 ABD Para Kaynağını 9.000 kat saklayabileceğiniz anlamına gelir (~ 10.000 Milyar Dolar). Diğer dünya para birimlerini kullanmanız için size yeterince yer verilmesi, muhtemelen, aşırı enflasyonu olan / olsa bile (merak ediyorsanız , 1 pound ekmeğin 3.000.000.000 mark olduğu WWI sonrası Alman enflasyonu konusuna bakın )

Uzun, çok hızlı devam etmek ve kolaydır gerektiğini size sadece integral işlemlerinde kullanan tüm faiz hesaplamalarını yapmak için yeterli oda ver eİş cevabı o nasıl yapılacağına ilişkin bir açıklama verir.


2

Buna ne kadar iş koymak istersiniz? Doğruluk ne kadar önemlidir? Yuvarlama ile meydana gelen kesirli hataları ve bir ikili sistemde ondalık sayıları temsil etmedeki yanlışlığı izlemeye önem veriyor musunuz?

Sonunda, "köşe kasaları" ve bilinen sorunlu durumlar için birim testlerini kodlamak ve uygulamak için biraz daha fazla zaman harcama eğilimindeyim - bu yüzden, keyfi olarak büyük miktarları içeren ve kesirli bitleri BigDecimal ya da büyük olanları içeren bakımdan değiştirilmiş bir BigInteger açısından düşünüyorum. Bir BigRational bölümü (iki büyükInteger, biri payda için diğeri pay için diğeri) - ve fraksiyonel kısmı ana BigInteger'e kesirli olmayan bir parça ekleyerek (belki de sadece periyodik olarak) kesir kısmı gerçek bir kesir olarak tutacak kodu içerir. Daha sonra, kesirli parçaları GUI hesaplamaları dışında tutmak için dahili olarak her şeyi sent içerisinde izlerdim.

Muhtemelen bir (basit) oyun için karmaşık bir yol - ama açık kaynak olarak yayınlanan bir kütüphane için iyi! Kesirli parçalarla uğraşırken performansı iyi tutmanın yollarını bulmanız gerekir ...


1

Kesinlikle yüzmüyorum. Sadece 7 hane ile, sadece aşağıdaki gibi hassasiyete sahipsiniz:

12,345.67 123,456.7x

Görüyorsun ya, zaten 10 ^ 5 dolarla, para biriktiriyorsun. double, gerçek hayatta değil, doğruluk endişeleri nedeniyle oyun amaçlı kullanılabilir.

Ancak uzun (ve bununla demek istediğim, 64 bit ya da C ++ 'da uzun) demek, işlemleri takip edip özetleyecekseniz yeterli değildir. Herhangi bir şirketin net varlıklarını korumak yeterlidir, ancak bir yıl boyunca yapılan tüm işlemler taşabilir. Bu, mali "dünyanızın" oyunda ne kadar büyük olduğuna bağlıdır.


0

Buraya ekleyeceğim başka bir çözüm de para sınıfı yapmak. Sınıf, bunun gibi bir şey olurdu (bir yapı bile olabilir).

class Money
{
     string currencyType; //the type of currency example USD could be an enum as well
     bool isNegativeValue;
     unsigned long int wholeUnits;
     unsigned short int partialUnits;
}

Bu, bu durumda kuruşları bir tamsayı olarak ve tüm dolarları bir tamsayı olarak temsil etmenizi sağlar. Negatif olmak için ayrı bir bayrağa sahip olduğunuzdan, olası miktarını ikiye katlayan değerleriniz için imzasız tamsayıları kullanabilirsiniz (bu fikri GERÇEKTEN büyük sayıları almak için bu fikri uygulayan bir sayı sınıfı da yazabilirsiniz). Yapmanız gereken tek şey matematik operatörlerini aşırı yüklemek ve bunu herhangi bir eski veri türü gibi kullanabilirsiniz. Daha fazla bellek kaplıyor, ancak değer sınırlarını gerçekten genişletiyor.

Bu, tüm birimlerdeki kısmi birim sayısı gibi şeyleri içerecek şekilde genişletilebilir, böylece 100 alt birimden başka bir şey için alt para birimleri olabilir; bu durumda sent başına dolar olabilir. Örneğin, bir floop oluşturan 125 floop olabilir.

Düzenle:

Ayrıca, tüm diğer para birimleri karşısında para birimi için döviz kuru sağlayabilecek para sınıfının erişebileceği türden bir tabloyu da inceleyebileceğiniz fikrini genişleteceğim. Bunu operatörünüzün aşırı yükleme fonksiyonlarına dahil edebilirsiniz. Bu nedenle, otomatik olarak 4 ABD Doları ile 4 İngiliz Sterlini eklemeye çalışırsanız, otomatik olarak 6,6 Sterlin (yazı olarak) verecektir.



-1

Sınıfı kullanmak en iyisidir. Paranızın uygulanmasını gizleyebilir, dilediğiniz zaman istediğinizi istediğiniz zaman çift / uzun olarak değiştirebilirsiniz.

Örnek

class Money
{
    private long count;//Store here what ever you want in what type you want i suggest long or int
    //methods constructors etc.
    public String print()
    {
        return count/100.F; //convert this to string
    }
}

Kodunuzda basitçe getter kullanmak bence daha iyi bir yoldur ve daha kullanışlı yöntemler saklayabilirsiniz.

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.