Conversione di stringhe in numeri interi senza utilizzare la moltiplicazione C #


9

C'è un modo per convertire una stringa in numeri interi senza usare la moltiplicazione. L'implementazione di int.Parse () utilizza anche la moltiplicazione. Ho altre domande simili in cui è possibile convertire manualmente la stringa in int, ma ciò richiede anche il mulitiplying del numero per la sua base 10. Questa è stata una domanda di intervista che ho avuto in una delle interviste e non riesco a trovare alcuna risposta al riguardo.


3
con (testo) o senza (titolo)?
D4z

2
Potresti chiarire? Il tuo titolo dice "senza" usare mentre il tuo testo dice "con" usando ...
vonludi

1
Considerando il resto del contenuto della domanda (ad es. "Ma ciò richiede anche la moltiplicazione del numero per la sua base 10"), il titolo è corretto. Inoltre, se è consentita la moltiplicazione, questo è banale, quindi non avrebbe senso chiederlo.
Giovanni

7
questo articolo suggerisce di sostituire la moltiplicazione per dieci con bit-shift e addizione ( x<<1 + x<<3), ma è ancora un modo di usare la moltiplicazione, quindi è difficile dire se sia "nello spirito" della domanda ...
Simon MᶜKenzie

3
Non for (int i = 0; i < 10; i++) result += number;contare?
canton7,

Risposte:


12

Se si assume un sistema numerico in base 10 e si sostituisce la moltiplicazione per turni di bit ( vedere qui ), questa può essere una soluzione per numeri interi positivi .

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

    return number;
}

Vedi l'esempio su ideone .

L'unico presupposto è che i caratteri '0'di '9'trovano direttamente accanto all'altro nel set di caratteri. I caratteri numerici vengono convertiti nel loro valore intero utilizzando character - '0'.

Modificare:

Per numeri interi negativi questa versione ( vedi qui ) funziona.

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;
}

In generale dovresti prendere in considerazione errori come controlli null, problemi con altri caratteri non numerici, ecc.


6

Dipende. Stiamo parlando dell'operazione logica della moltiplicazione o di come viene effettivamente eseguita nell'hardware?

Ad esempio, è possibile convertire una stringa esadecimale (o ottale o qualsiasi altro moltiplicatore di base due) in un numero intero "senza moltiplicazione". Puoi andare carattere per carattere e mantenere oring ( |) e bitshifting ( <<). Questo evita di usare l' *operatore.

Fare lo stesso con le stringhe decimali è più complicato, ma abbiamo ancora un'aggiunta semplice. Puoi usare i loop in aggiunta per fare la stessa cosa. Abbastanza semplice da fare. Oppure puoi creare la tua "tabella di moltiplicazione" - si spera che tu abbia imparato a moltiplicare i numeri a scuola; puoi fare la stessa cosa con un computer. E, naturalmente, se si utilizza un computer decimale (anziché binario), è possibile eseguire lo "spostamento dei bit", proprio come con la stringa esadecimale precedente. Anche con un computer binario, puoi usare una serie di bit-shift - (a << 1) + (a << 3)è lo stesso di a * 2 + a * 8 == a * 10. Attento ai numeri negativi. Puoi capire molti trucchi per renderlo interessante.

Naturalmente, entrambi sono solo moltiplicazioni sotto mentite spoglie. Questo perché i sistemi numerici posizionali sono intrinsecamente moltiplicativi . Ecco come funziona quella particolare rappresentazione numerica. Puoi avere semplificazioni che nascondono questo fatto (ad esempio solo i numeri binari hanno bisogno 0e 1, quindi invece di moltiplicare, puoi avere una condizione semplice - ovviamente, quello che stai davvero facendo è ancora la moltiplicazione, solo con solo due possibili input e due possibili uscite), ma è sempre lì, in agguato. <<è lo stesso * 2, anche se l'hardware che esegue l'operazione può essere più semplice e / o più veloce.

Per eliminare del tutto la moltiplicazione, è necessario evitare di utilizzare un sistema posizionale. Ad esempio, i numeri romani sono additivi (si noti che effettivi numeri romani non hanno usato le regole compattificazione che abbiamo oggi - quattro sarebbe IIII, non IV, e quattordici potevano essere scritti in qualsiasi forma come XIIII, IIIIX, IIXII, VVIIIIetc.). La conversione di una tale stringa in intero diventa molto semplice: basta andare carattere per carattere e continuare ad aggiungere. Se il personaggio è X, aggiungi dieci. SeV , aggiungi cinque. SeI, Aggiungi uno. Spero che tu possa capire perché i numeri romani sono rimasti popolari per così tanto tempo; i sistemi numerici posizionali sono meravigliosi quando è necessario fare molta moltiplicazione e divisione. Se hai a che fare principalmente con l'addizione e la sottrazione, i numeri romani funzionano alla grande e richiedono molta meno istruzione (e un abaco è molto più facile da fare e da usare rispetto a un calcolatore di posizione!).

Con incarichi come questo, c'è molto da perdere su ciò che l'intervistatore si aspetta davvero. Forse vogliono solo vedere i tuoi processi di pensiero. Abbracci i tecnicismi ( <<non è in realtà una moltiplicazione)? Conosci la teoria dei numeri e l'informatica? Ti immergi semplicemente nel tuo codice o chiedi chiarimenti? Lo vedi come una sfida divertente, o come un'altra enigmatica domanda di intervista che non ha alcuna rilevanza per il tuo lavoro? Per noi è impossibile dirti la risposta che l'intervistatore stava cercando.

Ma spero di averti almeno dato un'idea delle possibili risposte :)


Se utilizziamo il sistema numerico romano, come aggiungeresti se avessimo caratteri come B, T, S, R, G, A ecc. Che non fanno parte del sistema numerico romano. In altre parole, come otterrebbe un equivalente int?
Adheesh,

@Adheesh Non ho idea di cosa stai cercando di chiedere. Puoi fare un esempio di quello che pensi possa essere un problema?
Luaan,

Supponiamo di avere una stringa "12345" e di convertirla in un int. E se non volessi usare il sistema numerico posizionale e invece usare il sistema numerico romano. Come potremmo farlo? (Non voglio usare affatto la moltiplicazione)
Adheesh,

@Adheesh In un sistema numerico romano, la stringa non sarebbe "12345". Questo è il punto. I sistemi numerici posizionali sono intrinsecamente moltiplicativi. Il sistema numerico romano è additivo. La stringa romana sarebbe simile a "MMMMMMMMMMMMCCCXXXXIIIII". Vai carattere per carattere e continua ad aggiungere numeri.
Luaan,

@Adheesh Naturalmente, nella realtà pratica reale, non sarebbe un casino così lungo e ingombrante. Invece di "12345 metri", diresti qualcosa del tipo "XII chilo e CCCXXXXIIIII metri" o simili. I vecchi sistemi di misurazione erano adattati a persone che non potevano contare molto: basta confrontare la gamma di valori che puoi rappresentare con le unità imperiali con le unità moderne se puoi contare solo fino a dodici :)
Luaan

5

Considerando che si tratta di una domanda di intervista, la performance potrebbe non essere una priorità. Perché non solo:

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.
}

Se la stringa passata non è un numero intero, il metodo genererà un'eccezione di overflow.


1
Fantastico: P Assicurati di non usarlo se non ci sono feedback immediati da parte dell'intervistatore, però: DI immagina che potrebbero esserci anche modi per migliorare le prestazioni con partite parziali, usando lo stesso approccio di base. Per lo meno, un semplice controllo per i numeri negativi ti fa risparmiare metà del ciclo; un controllo per dispari / anche un'altra metà.
Luaan,

@Luaan Volevo farlo nel minor numero di righe possibile :) ...public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
nl-x

Purtroppo, esploderà: D Ma è un'ottima soluzione per scrivere il codice su carta - lo rende ovviamente molto corretto ed è difficile scrivere male. Puoi anche usare LIINQ - Enumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue.
Luaan,

0

Qualsiasi moltiplicazione può essere sostituita da un'aggiunta ripetuta. Quindi puoi sostituire qualsiasi moltiplicazione in un algoritmo esistente con una versione che utilizza solo l'aggiunta:

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;
}

Potresti andare oltre e scrivere una stringa specializzata in Int usando questa idea che minimizza il numero di aggiunte (numero negativo e gestione degli errori omessi per brevità):

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;
}

Ma non penso che valga la pena, dato che le prestazioni non sembrano essere una preoccupazione qui.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.