Bir dilde çok büyük sayıları ele alamıyor musunuz?


15

Eğer dil yapısı belirli bir değerden daha büyük sayıları idare edemez ise son derece büyük sayılar (sonsuz - intergers hiçbir şamandıralar) üzerinde hesaplamalar yapmak nasıl gitmek düşünmeye çalışıyorum.

Eminim bu soruyu soran ilk veya son kişi değilim ama kullandığım arama terimleri bana bu durumları ele almak için bir algoritma vermiyor. Aksine, çoğu öneri bir dil değişikliği veya değişken bir değişiklik sunar veya aramayla alakasız görünen şeyler hakkında konuşur. Bu yüzden küçük bir rehberliğe ihtiyacım var.

Böyle bir algoritma çizerdim:

  1. Dil için tamsayı değişkeninin maksimum uzunluğunu belirleyin.

  2. Bir sayı, değişkenin maksimum uzunluğunun yarısından fazla ise, onu bir diziye böler. (biraz oyun odası verin)

  3. Dizi sırası [0] = en sağdaki sayılar [n-max] = en soldaki sayılar

    Ör. Num: 29392023 Dizi [0]: 23, Dizi [1]: 20, dizi [2]: 39, dizi [3]: 29

Değişken uzunluğunun yarısını işaretleme noktası olarak belirlediğimden, bunları, onda birini, yüzüncü, vb. Hesaplayabilirim. Bir değişken maksimum uzunluk 0'dan 9999999999'a 10 basamaksa, o zaman biliyorum ki bunu beş basamağa bölerek bana oyun odası ver.

Bu nedenle, ekler veya çarparsam, [0] dizisinin altıncı basamağının (sağdan) dizinin [1] ilk basamağıyla (sağdan) aynı olduğunu gören değişken denetleyici işlevine sahip olabilirim.

Bölme ve çıkarma işlemlerinin henüz düşünmediğim kendi sorunları var.

Programın yapabileceğinden daha büyük sayıları desteklemenin en iyi uygulamalarını bilmek istiyorum.


1
Akla ilk gelen şey Java'nın BigInteger'ı: docs.oracle.com/javase/6/docs/api/java/math/BigInteger.html
Ivan

Buradaki herkesin bildiği ve belirli önerilerde bulunabileceği bir dil mi, yoksa belirsiz ve tescilli bir şey mi?
SinirliWithFormsDesigner

Bunu hangi dilde istediğimi bilmiyorum. Ben en php biliyorum ama o dilde yapmak istemiyorum. Lisp çekici çünkü okuduğum kadarıyla uzunluk sınırı yok. Bununla birlikte, nasıl çalıştığını bilmek istemem kişisel kusurum, bir adada sıkışmış olsaydım bunu qbasic'te yapma özgürlüğüne sahip olmamı istiyor. (Bu da eğlenmek için, her zaman büyük sayıları hesaplamayı düşünüyorum ve bazı çevrimiçi hesap makineleri görev için çok hantal.)
Mallow

Yanıtlar:


25

Çalıştığınız dil için rastgele bir hassas aritmetik ("çoklu kesinlik" veya "büyük num" olarak da bilinir) kitaplığı arıyorsunuz. Örneğin, C ile çalışıyorsanız GNU Bignum Kütüphanesini kullanabilirsiniz -> http://gmplib.org/

Nasıl çalıştığını anlamak istiyorsanız, kendi büyük num kütüphanenizi yazıp kullanabilirsiniz. Bunu ele almanın en basit yolu, her öğenin birlikte çalıştığınız sayının bir rakamı olduğu dizilerdir. Bundan sonra toplama, çıkarma, çarpma, bölme, üs alma vb. Tüm fonksiyonları yerine getirmeniz gerekir.


5
Tabii ki "basamak" görecelidir, birçok bignum kütüphanesi taban 256 (imzasız bayt []) ila 2 ^ 64 (imzasız uzun [])
cırcır

1
Anladığımdan emin olmak için, 'basamak' temel 256 basamaklı bir dizi olabilir mi? Sanırım yanıltıcı olabilirim, 256 tabanındaki matematik yapmak 88 tabanından daha kolay ama yine de oldukça bir görev ... (En azından dün gece bir kağıda haha ​​yaptığımda haha)
Mallow

1
"256 tabanındaki matematik yapmak 88 tabanından daha kolaydır". Yanlış. Aynı derecede kolaydır.
S.Lott

2
@ S.Lott: um ... mevcut bitsel işlemleriniz varsa, 256 tabanındaki matematik yapmak 88 tabanından kesinlikle daha kolaydır.
Jason S

1
Kendi toplama / çıkarma / çarpma işlemlerinizi oluşturmak oldukça basittir. Bununla birlikte, koşullu çıkarma ve bit kaydırmada bir egzersiz haline geldiği sürece, ikili olarak uygulamadığınız sürece, bölüm zordur.
Jason S

13

Bilinen bir sorundur: Keyfi hassasiyet aritmetiği

Kullandığınız dil bu sorunu çözmezse, önce bunu yapan bir üçüncü taraf kitaplığı bulmaya çalışın. Bulamazsanız veya merak ediyorsanız, uygulamayı deneyin; wikipedia makalesinin klasik uygulamalara iyi referansları vardır.


6

Büyük sayılarla uğraşırken, muhtemelen en temel tasarım kararlarından biri, büyük sayıyı nasıl temsil edeceğim?

Bir dize mi, bir dizi mi, bir liste mi yoksa özel (evde yetiştirilen) depolama sınıfı mı olacak.

Bu karar verildikten sonra, gerçek matematik işlemleri daha küçük parçalara bölünebilir ve daha sonra int veya integer gibi yerel dil türleriyle yürütülebilir.

Ben bir dize olarak ortaya çıkan çok sayıda depolayan C # .Net çok temel bir EK örnek dahil ettik . Gelen "numaralar" da dizelerdir, bu yüzden çok "büyük" numaralar gönderebilmelidir. Örneği basit tutmak için yalnızca tam sayılar için olduğunu unutmayın.

Dizelerde bile, burada gösterildiği gibi, karakter sayısında veya sayıdaki "sayılar" için bir sınır vardır:

.NET dizesinin olası maksimum uzunluğu nedir?

Ancak .Net için int32 veya int64 yerel türlerinin çok ötesinde gerçekten büyük sayılar ekleyebilirsiniz.

Her neyse, işte bir dize depolama uygulaması.

/// <summary>
/// Adds two "integers".  The integers can be of any size string.
/// </summary>
/// <param name="BigInt1">The first integer</param>
/// <param name="BigInt2">The second integer</param>
/// <returns>A string that is the addition of the two integers passed.</returns>
/// <exception cref="Exception">Can throw an exception when parsing the individual parts     of the number.  Callers should handle. </exception>
public string AddBigInts(string BigInt1, string BigInt2)
{
    string result = string.Empty;

    //Make the strings the same length, pre-pad the shorter one with zeros
    int length = (BigInt1.Length > BigInt2.Length ? BigInt1.Length : BigInt2.Length);
    BigInt1 = BigInt1.PadLeft(length, '0');
    BigInt2 = BigInt2.PadLeft(length, '0');

    int remainder = 0;

    //Now add them up going from right to left
    for (int i = (BigInt1.Length - 1); i >= 0; i--)
    {
        //If we don't encounter a number, this will throw an exception as indicated.
        int int1 = int.Parse(BigInt1[i].ToString());
        int int2 = int.Parse(BigInt2[i].ToString());

        //Add
        int add = int1 + int2 + remainder;

        //Check to see if we need a remainder;
        if (add >= 10)
        {
            remainder = 1;
            add = add % 10;
        }
        else
        {
            remainder = 0;
        }

        //Add this to our "number"
        result = add.ToString() + result;
    }

    //Handle when we have a remainder left over at the end
    if (remainder == 1)
    {
        result = remainder + result;
    }

    return result;
}

Umarım bu, kendi uygulamanız hakkında size bazı fikirler verir. Örnek kodun muhtemelen optimize edilmediğini veya bunun gibi bir şey olduğunu lütfen unutmayın. Bunun nasıl yapılabileceği hakkında bazı fikirler vermek içindir.


Güzel!! Teşekkürler, kalıntıları temizlemeye yardımcı olur, bu ekstra biti fazla karmaşıklaştırırdım.
Ebegümeci

-2

Bu benim için daha hızlı çalışıyor:

static string Add(string a, string b)
        {
            string c = null;

            if (Compare(a, b) < 0)
            {
                c = a;
                a = b;
                b = c;
            }

            StringBuilder sb = new StringBuilder();

            b = b.PadLeft(a.Length, '0');

            int r = 0;

            for (int i = a.Length - 1; i >= 0; i--)
            {
                int part = a[i] + b[i] + r - 96;

                if (part <= 9)
                {
                    sb.Insert(0, part);

                    r = 0;
                }
                else
                {
                    sb.Insert(0, part - 10);

                    r = 1;
                }
            }

            if (r == 1)
            {
                sb.Insert(0, "1");
            }

            return sb.ToString();
        }

2
Bu site ile ilgili kavramsal soruları ve cevapları şeyleri açıklamak bekleniyor. Açıklama yerine kod dökümlerini atmak kodu IDE'den beyaz tahtaya kopyalamak gibidir: tanıdık gelebilir ve hatta bazen anlaşılabilir olabilir, ancak garip hissediyor ... sadece garip. Beyaz
Tahtanın

Bu site DEĞİŞİM, bu yüzden elimizden geldiğince yardım etmeye çalışıyoruz. Belki StackOverflow bu tür yorum yapmak gerekir, ama benim yaklaşım yardımcı olmaya çalıştım. Birisinin hala bir açıklamaya ihtiyacı varsa, bunu isteyecektir. Burada, sondan başlayarak basamaklı standart bir matematiksel toplama yapıyorum.
Andranik Sarkisyan

Tatarcık ile aynı fikirde. En azından kodu boşaltmadan önce algoritmayı açıklayın.
Frank Hileman

Sadece hiçbir açıklama yapmadan kodu boşaltma, kopyala-geç-git'i teşvik etmek gibidir. Bunun SoftwareEngineering'de nasıl yararlı olabileceğini anlamıyorum. Belki StackOverflow'dadır, ancak her iki sitenin de aslında tamamen farklı amaçları vardır.
LAIV
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.