Çarpma C # kullanmadan String'i Integer'e dönüştürme


9

Çarpma kullanmadan dizeyi tamsayılara dönüştürmenin bir yolu var mı? İnt.Parse () uygulaması da çarpma işlemini kullanır. Dizeyi int'e dönüştürebileceğiniz başka benzer sorularım var, ancak bu da taban 10 ile sayıyı çarpıştırmayı gerektiriyor.


3
ile (metin) veya olmadan (başlık)?
Ocak'ta

2
Açıklığa kavuşturabilir misiniz? Başlığınız 'kullanmadan'
diyorken

1
Sorunun içeriğinin geri kalanı dikkate alındığında (örn. "Ancak sayının temel 10 ile çarpılması da gerekir"), başlık doğrudur. Artı, çarpmaya izin verilirse bu önemsizdir, bu yüzden sormak mantıklı olmaz.
John

7
Bu makalede , çarpma işleminin on ile bit kaydırma ve toplama ( x<<1 + x<<3) kullanılarak değiştirilmesi
önerilmektedir

3
Önemli for (int i = 0; i < 10; i++) result += number;mi?
canton7

Yanıtlar:


12

Bir taban-10 sayı sistemi varsayarsanız ve çarpma işlemini bit kaydırmalarıyla değiştirirseniz ( buraya bakın ), bu pozitif tamsayılar için bir çözüm olabilir .

public int StringToInteger(string value)
{
    int number = 0;
    foreach (var character in value)
        number = (number << 1) + (number << 3) + (character - '0');

    return number;
}

Örneğe bakın ideone .

Sadece varsayım karakter olmasıdır '0'için '9'karakter kümesi birbirine doğrudan yanında yalan. Rakam karakterleri kullanılarak tamsayı değerlerine dönüştürülür character - '0'.

Düzenle:

İçin negatif tamsayılar bu sürümü ( burada bakınız ) çalışır.

public static int StringToInteger(string value)
{
    bool negative = false;
    int i = 0;

    if (value[0] == '-')
    {
        negative = true;
        ++i;
    }

    int number = 0;
    for (; i < value.Length; ++i)
    {
        var character = value[i];
        number = (number << 1) + (number << 3) + (character - '0');
    }

    if (negative)
        number = -number;
    return number;
}

Genel olarak, boş denetimler, sayısal olmayan diğer karakterlerle ilgili sorunlar vb. Hataları dikkate almalısınız.


6

Değişir. Çarpmanın mantıksal işleminden mi, yoksa aslında donanımda nasıl yapıldığından mı bahsediyoruz?

Örneğin, bir onaltılık (veya sekizli veya herhangi bir diğer temel iki çarpan) dizesini "çarpma olmadan" tamsayısına dönüştürebilirsiniz. Karakteri karaktere göre gidebilir ve oring ( |) ve bitshifting ( <<) yöntemlerini kullanabilirsiniz. Bu *operatörü kullanmaktan kaçınır .

Ondalık dizelerle aynısını yapmak daha zordur, ancak yine de basit bir eklentimiz var. Aynı şeyi yapmak için döngüler ek olarak kullanabilirsiniz. Yapması oldukça basit. Ya da kendi "çarpım tablonuzu" yapabilirsiniz - umarım okulda sayıları çarpmayı öğrendiniz; aynı şeyi bir bilgisayarla da yapabilirsiniz. Ve elbette, ondalık bir bilgisayardaysanız (ikili yerine), tıpkı önceki onaltılık dizgede olduğu gibi "bitshift" i yapabilirsiniz. İkili bir bilgisayarla bile, bir dizi bitshift kullanabilirsiniz - (a << 1) + (a << 3)aynıdır a * 2 + a * 8 == a * 10. Negatif sayılar konusunda dikkatli olun. Bunu ilginç kılmak için birçok püf noktası bulabilirsin.

Tabii ki, her ikisi de sadece kılık değiştirerek çarpmadır. Çünkü konumsal sayısal sistemler doğası gereği çarpıcıdır . Bu belirli sayısal temsil böyle çalışır. Bu gerçeği gizleyen basitleştirmelere sahip olabilirsiniz (örneğin, ikili sayılar sadece ihtiyaç duyar 0ve 1bu nedenle çarpmak yerine basit bir koşula sahip olabilirsiniz - elbette, gerçekte yaptığınız şey sadece çarpışma, sadece iki olası giriş ve iki olası çıktılar), ama her zaman orada, gizleniyor. işlemi yapan donanım daha basit ve / veya daha hızlı olsa bile <<aynıdır * 2.

Çarpmayı tamamen ortadan kaldırmak için konumsal bir sistem kullanmaktan kaçınmanız gerekir. Örneğin, romen rakamları katkı (- dört olacağını fiili romen rakamları bugün var kompaktikasyon kurallarını kullanabilirsiniz etmediğini not vardır IIII, değil IVve o on dört gibi herhangi bir biçimde yazılmış olabilir XIIII, IIIIX, IIXII, VVIIIIvb.) Böyle bir dizeyi tamsayıya dönüştürmek çok kolay hale gelir - sadece karakter karakter gidin ve eklemeye devam edin. Karakter ise X, on ekleyin. Eğer Vbeş tane ekleyin. EğerI, ekleyin. Umarım Romen rakamlarının neden bu kadar uzun süre popüler kaldığını görebilirsiniz; çok sayıda çarpma ve bölme yapmanız gerektiğinde konumsal sayısal sistemler harikadır. Esas olarak toplama ve çıkarma ile uğraşıyorsanız, romen rakamları harika çalışır ve çok daha az okul gerektirir (ve bir abaküs yapmak ve konum hesaplayıcıdan çok daha kolaydır!).

Bunun gibi ödevlerle, görüşmecinin gerçekte ne beklediği konusunda çok fazla hit ve özledim. Belki de sadece düşünce süreçlerinizi görmek isterler. Teknikleri kucaklıyor musunuz ( gerçekten çarpma <<değil )? Sayı teorisi ve bilgisayar bilimi biliyor musunuz? Sadece kodunuzla devam mı ediyorsunuz yoksa açıklama mı istiyorsunuz? Bunu eğlenceli bir meydan okuma olarak mı, yoksa işinizle hiçbir ilgisi olmayan başka bir saçma sıkıcı röportaj sorusu olarak mı görüyorsunuz? Size görüşmecinin aradığı cevabı söylememiz imkansız.

Ama umarım en azından sana olası cevaplara bir göz atacağım :)


Romen rakam sistemini kullanırsak, Roma rakam sisteminin bir parçası olmayan B, T, S, R, G, A vb. Karakterlerimiz olsaydı nasıl eklersiniz? Başka bir deyişle, int eşdeğeri nasıl elde edilir?
Ocak'ta Adheesh

@Adheesh Ne sormaya çalıştığına dair hiçbir fikrim yok. Sorun olacağını düşündüğünüze bir örnek verebilir misiniz?
Luaan

Bir "12345" dizemiz olduğunu ve bunu bir int'e dönüştürmek istediğimizi varsayalım. Konumsal sayısal sistemi kullanmak yerine romen rakam sistemini kullanmak istemezsem ne olur? Bunu nasıl yapabiliriz? (Çarpmayı hiç kullanmak istemiyorum)
Adheesh

@Adheesh Romen rakamlı bir sistemde, dize "12345" olmaz. Bütün mesele bu. Konumsal sayısal sistemler doğal olarak çoğaltıcıdır. Romen rakamı sistemi toplanır. Roma dizgisi "MMMMMMMMMMMMCCCXXXXIIIII" gibi bir şey olacaktır. Karakter karakter ilerleyin ve sayı eklemeye devam edin.
Luaan

@Adheesh Tabii ki, gerçek pratik gerçeklikte, bu kadar uzun hantal bir karmaşa olmazdı. "12345 metre" yerine "XII kilo ve CCCXXXXIIIII metre" gibi bir şey söyleyebilirsiniz. Eski ölçüm sistemleri çok fazla sayılamayan insanlara uyarlandı - sadece on
ikiye

5

Bir görüşme sorusu olduğu düşünüldüğünde, performans yüksek bir öncelik olmayabilir. Neden sadece:

private int StringToInt(string value)
{
    for (int i = int.MinValue; i <= int.MaxValue; i++)
        if (i.ToString() == value)
            return i;
    return 0; // All code paths must return a value.
}

Geçirilen dize bir tamsayı değilse, yöntem bir taşma istisnası atar.


1
Parlak: P Görüşmeciden hemen bir geri bildirim yoksa bunu kullanmadığınızdan emin olun: DI aynı temel yaklaşımı kullanarak kısmi eşleşmelerle performansı artırmanın yollarının bile olabileceğini hayal edin. En azından, negatif sayılar için basit bir kontrol sizi döngünün yarısını kurtarır; tek / yarım başka bir kontrol.
Luaan

@Luaan Mümkün olduğunca küçük çizgilerle yapmak istedim :) ...public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
nl-x

Ne yazık ki, bu patlayacak: D Ama kodu kağıda yazmak için harika bir çözüm - çok açık bir şekilde doğru yapıyor ve yanlış yazmak zor. Ayrıca LIINQ - kullanabilirsiniz Enumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue.
Luaan

0

Herhangi bir çarpma işlemi tekrarlanan ekleme ile değiştirilebilir. Böylece, var olan bir algoritmada herhangi bir çarpımı yalnızca ek kullanan bir sürümle değiştirebilirsiniz:

static int Multiply(int a, int b)
{
    bool isNegative = a > 0 ^ b > 0;
    int aPositive = Math.Abs(a);
    int bPositive = Math.Abs(b);
    int result = 0;
    for(int i = 0; i < aPositive; ++i)
    {
        result += bPositive;
    }
    if (isNegative) {
        result = -result;
    }
    return result;
}

Ekleme sayısını en aza indiren bu fikri kullanarak Int'ye özel bir String yazabilirsiniz (negatif sayı ve kısalık için hata işleme atlandı):

static int StringToInt(string v)
{
    const int BASE = 10;
    int result = 0;
    int currentBase = 1;
    for (int digitIndex = v.Length - 1; digitIndex >= 0; --digitIndex)
    {
        int digitValue = (int)Char.GetNumericValue(v[digitIndex]);
        int accum = 0;
        for (int i = 0; i < BASE; ++i)
        {
            if (i == digitValue)
            {
                result += accum;
            }
            accum += currentBase;
        }
        currentBase = accum;
    }
    return result;
}

Ancak performansın endişe kaynağı olmadığı için bunun zahmete değeceğini düşünmüyorum.

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.