Boşta kalma oyunları bu kadar büyük sayıları nasıl ele alıyor?


31

Tap titans ve Cookie Clicker gibi oyunların bu kadar büyük rakamlarla nasıl başa çıktıklarını merak ediyorum.

Boşta bir oyun uygulamaya çalışıyorum, ancak C # tarafından desteklenen en büyük sayı biçimi ondalık.

10 ^ 500’e kadar destek arıyorum; kayan nokta olması gerekiyor

Bununla nasıl başa çıkabilirim?

PS, çapraz platform yani pc, mac, ios, android ve Unity ile uyumlu olması gerekiyor


2
Doğru hatırlıyorsam, Cookie
Clicker'ın

Hayır, Çerez Tıklayıcısı'nı zaten aklımdan bloke etmiştim!
Arturo Torres Sánchez

2
Bir Unity oyunu olan TimeClickers'ın ayrıştırılmış kaynağına baktım . Sadece kullanıyorlar double. Ben olsaydım , yine de BigInteger kullanırdım .
BlueRaja - Danny Pflughoeft

1
@VioletGiraffe: Ben de aynı fikirdeyim ve (bizim?) Şüphelerimi somutlaştırmak istiyorum (OP'nin soruyu daha net hale getirmesine yardımcı olmak için): Soruyla ilgili "boşta oyun" nedir oyunun büyük sayılar için özel bir durum)? Ne tür sayılar " bu kadar büyük sayılar" (kendi başıma vurgularım) anlamına gelir? Sayıların ne kadar büyük olmasını istersiniz?
VEYA Eşleştiricisi,

Her zaman bu kadar büyük bir sayıyı bir dizgide saklayabilir ve dizgede toplama yapmak için kolayca bir işlev uygulayabilirsiniz.
dev-masih

Yanıtlar:


40

Kesin sayıları tam bir doğruluk olmadan depolamak istiyorsanız, örneğin 12.567.000.000.000, 12.567T (trilyon) olarak gösterecekseniz, sadece standart şamandıra / ondalık değerleri kullanıp ilk x önemli rakamları uygun bir sonekle gösterebilirsiniz. bunun gibi. Octillions'dayken, her bir tamsayı artışına gerçekten dikkat etmeniz gerekiyor mu?


4
Muhtemelen gerçekten en mantıklı cevap budur ve Cookie Clicker'ın sadece JavaScript'te standart bir araç kullandığından oldukça eminim - "hacklediğim" (okuma: konsolla karışık) ve sayı 1e308'e ulaştığında "Infinity" ve istediğim bir şeyi almaya devam edebilirim XD
Niet the Dark Absol,

1
Harika! Metnin "Sonsuzluk" a sıçraması, geliştirici gibi hissediyor olması da bu olayla ilgili savunmada kod yazıyordu. Ayrıca, sadelik kraldır.
Ross Taylor-Turner

19
@RossTurner - "Sonsuzluk" metnini göstermesiyle ilgili hiçbir kodlama muhtemelen yoktur - sonsuzluk bir yüzgecin sahip olabileceği bir değerdir ve JavaScript, diğer birçok dilde olduğu gibi nasıl gösterileceğini bilir.
Jibb Smart,

Standart değişkenler (çift duyarlık, 8 bayt), orijinal soru gerektirdiğinden 10 ^ 500'e kadar sayıları temsil etmesine izin vermez, ~ 10 ^ 300 değerine çıkar. Bu yeterli değilse, dile bağlı olarak önemsiz olabilecek dört hassas yüzer kullanmalısınız.
Peteris

1
Her programcının kayan nokta sayıları hakkında bilmesi gerekenler: floating-point-gui.de
Steve

20

BigInteger gibi bir şey kullanabilirsiniz , ancak .net 4.0'da yanılmıyorsam (tüm birlik oluşturma platformları tarafından desteklenmiyor).

Ancak bu işlevi .net4.0 gerekliliği olmadan getirmeye çalışan bazı kütüphaneler vardır. Mesela burada .

Alternatif olarak, çarpanı takip ederek daha büyük olanı temsil etmek için daha küçük sayıları kullanabilirsiniz. Örneğin:

double value = 9;
enum Multiplier {
   Hundred,
   Thousand,
   Million,
   Billion,
   Trillion
}

Şimdi, 9 değerine sahip olsanız bile, çarpanınızla birleştirirseniz, bu 9'u 9 trilyon kadar etkili bir şekilde temsil edebilirsiniz (Ya "trilyon" koyarak ya da değerinizin sonuna sıfır ekleyecek bir şey yazarak) ).


BigIntegerSayıların bir String veya Byte [] gösterimini kullanma gibi sınıfların - bu nedenle gerçekte, iki "sayıyı Dizeler veya Baytlar" ekleyen ve çıkartan kendi sınıflarını oluşturabileceklerini belirtmek önemlidir. İhtiyacınız yok ama çarpımı veya bölmeyi ya da diğer daha gelişmiş işlevleri de destekleyebilirsiniz. ) - ancak bellekten kaçabilecekleri her zaman fiziksel bir sınır olduğunu akıllarında tutmaları gerekir.
DoubleDouble,

1
Her bir bayt, numaranızın boyutunu 256 ile çarpar. Bir numarayı temsil etmeye çalışırken hafızanız tükenirse, numaranızın yine de hiçbir gerçek değeri yoktu. 256 ^ (2 milyar) = 2 ^ 8 ^ (2 milyar) = 2 ^ (16 milyar) ~ = 10 ^ (5 milyar) (wolframalpha bu son dönüştürmeyi yapmaya çalışırken bozuldu). Gözlemlenebilir evrende tek tek Planck hacimlerini, 150 basamak (<500 bit) kullanarak belirleyebilirsiniz.
Michael,

11

Birlik'te kullanmak için kendi sınıfınızı yazmanız gerekebilir, ancak bu özellikle zor olmazdı.

Dahili olarak, listedeki List<int>her eleman 9 basamaklı bir gruba karşılık gelen bir tamsayı listesi (örneğin a ) olabilir. Her bir tamsayı 0 ila 999 999 999 aralığında olacaktır. Bir tamsayı 2 milyardan biraz fazlasını destekleyebilir ve imzasızsa iki katına çıkartabilir, ancak istediğiniz her "basamak" taşmasını 1 000 000 000isteyebilirsiniz, çünkü Kolayca büyük sayınızı görüntüleme için bir dizgeye dönüştürebilmek için. Zaten ondalık basamak olanları birleştirmek ( return group[i].ToString() + group[i-1].ToString() and so on), herhangi bir normal veri türünün aralığının dışındaki grupların toplamının nasıl görüntüleneceğini bulmaktan daha kolaydır .

Yani, listenizdeki ilk int 1leri temsil eder. Bir sonraki milyarlarca sayısı olacaktır. Bir sonraki, katrilyon sayısı, vb.

Toplama ve çıkarma, taşmayı izlemek ve onu bir sonraki "basamağa" taşımak zorunda olduğunuz, kalem ve kağıt toplama ve çıkarma gibi çalışır, ancak 0-9 aralığındaki rakamlar yerine rakamlarınız 0 ila 999 999 999.


10

Büyük sayıları idare etmek için , Kahraman Kulesi gibi iyi bir örnek olduğunu düşündüğüm şeye bakardım . Sol üst köşe:

1

2
(kaynak: mzstatic.com )

Oynanmaya başlamadan, sayıları yönetme şekli oldukça basittir: İki sayı yığını görüyorsunuz. Kulede yükseldikçe ve daha fazla "altın" yaptıkça, iki kova daha büyük sayıları temsil eder.

120 
120M320K - 120 Million
120B631M - 120 Billion
120T134B - 120 Trillion

Oyun T'yi geçtikten sonra a, b, c ... z, aa, ab, ...

56aa608z

Bu şekilde yapmak, oyunu detaylı bir şekilde aşağıya düşürmezken, ne kadar altın kazandığınızı bile bilmenizi sağlar.

Numaranız Trilyonlardan geçtiğinde Milyonları gerçekten umursuyor musunuz?

Sayıyı Int, Big Int, Float, Çift, Ondalık,… olarak mı tutar? Özel Dizi? Rakamları bu kadar "bulanık" bir şekilde tutarken, bunun önemli olduğunu sanmıyorum ...

Tüm bu muhtemel meseleler en önemli parçalardır - bu durumda, ilk 6 ... Bundan sonra, sonraki 3 ya da 6 MAYBE - birkaç yüz K kazanmanın Milyonlara katlanabileceği bir nokta - ama kazanmanın bir anlamı var birkaç yüz K, T'ye bastığınızda sizi etkilemeyecek ... çok daha az aa ve ötesi.

Kilometreniz değişecek (ne / ihtiyaç duyduğunuza bağlı olarak) ... 2c'imi iyi / basit bir örnek olduğunu düşündüğüm şeye koyacağımı düşündüm.

Düzenle:

Numaralandırma sistemini nasıl uygulayacağım üzerine düşünceler: 3 önemli bölümden oluşan bir numaraya sahip olurdum: XXXX.YYY (...) xZZZ.

X is the most significant digits, 
Y trailing 
Z the multiplier (multiple of 3).

Böylece 120.365x1 120k365 ... 120.365x2 120M365K ... vb olacaktır. 4 öncüye (1200.365x2) basınız, ardından 1.200365 (...) x3 sayılarını döndürünüz. Bam. 1B200M'iniz var.

XY bir Ondalık ya da Kayan noktaya kolayca sığardı ... Z yanında bir int / imzasız int olarak oturuyordu.

Bir şamandırala, noktadan sonra oldukça büyük - ama gittikçe önemsiz olan - hane sayısını koruyabilirsiniz.

Z kolayca anlaşılabilir bir sayı bloğunu kolayca temsil eder:

K = 1
M = 2
B = 3
T = 4
a = 5 
...
z = 31 (I may be off on this)
aa = 32
...
az = 58
ba = 59
...
...

1

Ve büyük sayılarla başa çıkmanın kolay yolu, birden fazla INTEGER değerinden sonra taşmaktan çok TAŞINIR. 16 Bitlik bir INT değerine (0 - 65535) sahipseniz ve bundan daha fazlasına sahip olmak istiyorsanız, arka arkaya iki adet 16 bitlik INT değeri kullanın. Bir BYTE değerine (0 ila 255) sahip olmak, ancak yalnızca 99 basamağa kadar değer kullanmak gibi düşünün. 100'e ulaştığında, faydalı bulduğunuz sayıda basamak için bir sonraki daha yüksek BYTE değerine yuvarlayın. Günümüzün GHZ bilgisayarlarında bile özensiz kodlama bile iyidir.

Tabii ki, biraz daha hızlı olan bir alternatif var.
Bir sayıya art arda 18 ekliyorsanız, 2'yi çıkarmak ve 20 eklemek daha kolay olur. 18, 36, 54, 72, 90, 108, ... 18 = 20 + (- 2).
Bu da İkili olarak çalışır. (Binary'de aynı ondalık değerler) 10010, 100100, 110110, 1001000
DEC (18) = BIN (10010)
Daha kolay İkili ayrıştırma işlemi dışında, 18 = 16 + 2
DEC (16 + 2) = BIN (10000 + 00010). Değer 15 ise, o zaman ikiliye 16 ekleyerek ve 1'i çıkarırken düşünün (10000-00001).

Bu şekilde, sayı parçalarını değer başına yönetilebilir sınırlar altında tutabilirsiniz.
Temel bir 16 bitlik INT değerini (0 ila 65535) 4 basamaklı bir ondalık sayı sınırına (0 ila 9999) sınırlamak için özensiz kodlama yöntemini kullanıyorsanız, yapmanız gereken tek şey değer 9999 sınırını aştığında, 9999 'u çıkartın ve onu bir sonraki değer öbeğine taşıyın (çünkü temelde sayılarla gerçek bir ikili hesaplamaya "ekler").

İdeal olarak, sadece ilkokulda öğrendiğiniz SEMBOLİK MATH'i kullanırsınız. Bu nasıl çalışıyor. 1 ondalık sembolünüz varsa ve 1 eklerseniz o zaman 2 ondalık sembolünü elde edersiniz. Bunu bir sembol olarak adlandırmamın nedeni, "IF sembol X (1) 'in arama tablosuna sahip herhangi bir sembol serisini kullanabilmenizdir. X (4) THEN çıkış sembolünden X (5) "sembolüne eklenir. X (1) sembolü bir kedinin resmi olabilir ve X (4) sembolü PERCENT işareti olabilir, ama önemli değil. Sembollerin var, o sembollerin birleştirilmesinden sonra ne olduğuna dair temel bir kural kitabı (çocukken ezberlediğiniz çarpım tabloları gibi) ve bu sembolün bu işlemin bir parçası olarak hangi sembollerle sonuçlanması gerektiğini. Symbolic Math'ı kullanarak, işlemcinizin sayısal sınırlarını hiçbir zaman gerçekten çağırmadan sonsuz sayıda basamak ekleyebilirsiniz.

Bunu kolay kodlamada yapmanın bir yolu, çalışmak istediğiniz her bir rakamın, büyük boyutlu bir dizilimde tek bir birim olarak çalışmasını sağlamaktır. 4096 ondalık basamağı (birim kutu başına 2 basamağı aşmayacak şekilde) göstermek istiyorsanız, 2 set 4096 BYTE dizisi konumu tahsis etmiş olursunuz. 1098874 değerinin saklanması, diziyi (1) (0) (9) (8) (8) (7) (4) olarak kullanacaktır. Buna 7756 değerini eklediyseniz, onu (7) (7) (5) (6) 'ya dönüştürür ve sonra eklersiniz. Sonuç, (1) (0) (9) (15) (15) (12) (10) olacaktır; bu durumda, tüm rakam kutuları değeri (0 - 9). En sağdaki (10) değer 10 çıkarılacak ve elde edilen değer sıfır (0) olacaktır ve (1) değerini (12) bir sonraki soldaki kutuya (12) taşıyacaktır (10). içine çıkarmak için çıkarıldı (3).


7
ÇOK ÇOK YELLING için -1
Slipp D. Thompson

5
Hey @Gridlock, tamamen yeni bir kullanıcı olduğunuzu farkettim - hoşgeldiniz. Aşırı oyumun kalıcı olmadığını açıklamalıyım; yapıcı eleştiri olarak düşünülmüştür. Verdiğiniz cevabın değeri var ve talep ettiğim düzeltmeyi yaptıktan sonra bunu bir artı oyuna dönüştürmekten çok mutlu olacağım. Ayrıca, SE'nin bir forum olmadığını unutmayın; iyi bir cevap okunmaz ve unutulmaz, ancak zaman içinde temettü ödemeleri öder. Cevaplarınızı burada & orada revize etmek topluluğa ve temsilcinize yardımcı olur. Umarım seni korkutmamışımdır; tekrar hoş geldiniz, umarım tavsiyemi kullanırsınız.
Slipp D. Thompson

1
Size sunacağım diğer bir öneri, tümü büyük harf yerine bazı temel Markdown biçimlendirmelerini kullanmak. Metni backtick'lere ( `text`text) sarma , tek aralıklı, kod parçaları, işlev adları, veriler vb. İçin uygun hale getirir. Metnin altını çizme veya yıldızlara italik ( _text_veya *text*metin ) koyma ve çift alt çizgi veya çift yıldız koyu ( __text__veya **text**metin ) yapacaktır .
Slipp D. Thompson

0

Yaptığınız şey birleştirilmiş birkaç değişkene sahip olmak ve sonra aralarındaki ekleme ve taşmayı kendiniz kontrol etmek. Bu şekilde istediğiniz sayıda haneye sahip olabilirsiniz. 10.000 adet 32 ​​bit tam sayı birleştirin ve ihtiyacınız olan şey buysa, 32.000 bitlik bir sayıya sahipsiniz. Herhangi bir programlama dilinde sınırlama yoktur. Tek sınır, neyi çözebildiğinizdir.


Oy vermeyenler için nedenini açıklayabilir misiniz? Bu popüler bir çözüm değildir, ya da sıfır çaba gerektirir biri bile, yine de bir çözüm, ve sen dilleri / desteklemeyen platformlarda aynı hatta yapmaya izin verebilir bir doubleveya BigInteger.
TomTsagk
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.