乗算C#を使用せずに文字列を整数に変換する


9

乗算を使用せずに文字列を整数に変換する方法はありますか?int.Parse()の実装も乗算を使用します。文字列をintに手動で変換できる他の同様の質問がありますが、これには、その基数10で数値を乗算する必要があります。これは、インタビューの1つで受けたインタビューの質問であり、これに関する答えを見つけることができません。


3
(テキスト)の有無(タイトル)は?
d4zed

2
明確にしてもらえますか?タイトルに「なし」を使用しているのに対し、テキストに「あり」を使用しているのは...
vonludi

1
質問の内容の残りの部分(例:「これにも10を底とする数が必要です」など)を考慮すると、タイトルは正しいです。さらに、乗算が許可されている場合、これは取るに足らないことなので、それを要求しても意味がありません。
ジョン

7
この記事では、乗算をビットシフトと加算(x<<1 + x<<3)で10に置き換えることを提案していますが、それでも乗算を使用する方法であるため、それが問題の「精神」にあるかどうかは
わかりませ

3
for (int i = 0; i < 10; i++) result += number;カウントしますか?
canton7

回答:


12

10を基数とするシステムを想定し、ビットシフトによる乗算に置き換えた場合(ここを参照)、これは正の整数の解決策となります

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

    return number;
}

ideoneの例を参照してください。

唯一の仮定は文字があることを'0'する'9'文字セットで互いに直接隣にあります。数字文字は、を使用して整数値に変換されますcharacter - '0'

編集:

以下のために負の整数このバージョンは(ここを参照してください)動作します。

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

一般的に、nullチェック、その他の非数値文字の問題などのエラーを考慮する必要があります。


6

場合によります。乗算の論理演算について話しているのか、それとも実際にハードウェアでそれを行うのか?

たとえば、16進数(または8進数、またはその他の2乗法)文字列を「乗算なし」の整数に変換できます。文字ごとに移動して、oring(|)とbitshifting()を続けることができ<<ます。これにより、*演算子の使用が回避されます。

10進文字列で同じことを行うのは難しいですが、単純な追加がまだあります。ループを追加で使用して同じことを行うことができます。とても簡単です。または、独自の「乗算表」を作成することもできます。うまくいけば、学校で数値を乗算する方法を学びました。コンピュータでも同じことができます。もちろん、(バイナリではなく)10進数のコンピュータを使用している場合は、以前の16進数文字列と同じように「ビットシフト」を実行できます。バイナリコンピュータでも、一連のビットシフトを使用できます。これ(a << 1) + (a << 3)はと同じa * 2 + a * 8 == a * 10です。負の数に注意してください。あなたはこれを面白くするためにたくさんのトリックを理解することができます。

もちろん、これらはどちらも変装しただけの乗算です。これは、位置数値システムが本質的に乗法であるためです。これが、特定の数値表現が機能する方法です。この事実を隠す簡略化を行うことができます(たとえば、2進数では0and のみが必要な1ので、乗算する代わりに、単純な条件を設定できます。もちろん、実際に実行しているのは、まだ2つの入力と2つの可能性があるだけの乗算です。出力)、しかしそれは常にそこにあり、潜んでいます。操作を実行するハードウェアがより単純または高速である場合でも、はと<<同じ* 2です。

乗算を完全になくすには、位置システムの使用を避ける必要があります。例えば、ローマ数字は加法的である(実際のローマ数字は、我々が今日持っているコンパクト化ルールを使用していないことに注意してください- 4は次のようになりIIII、ないIV、それ14のような任意の形式で書くことができXIIIIIIIIXIIXIIVVIIIIなど)。そのような文字列を整数に変換することは非常に簡単になります-文字ごとに行き、追加し続けるだけです。文字がの場合、X10を追加します。の場合V、5を追加します。もしI、1つ追加します。なぜローマ数字がそれほど長い間人気を保っていたのか、理解していただければと思います。位置数値システムは、多くの乗算と除算を実行する必要がある場合に最適です。主に足し算と引き算を扱う場合、ローマ数字はうまく機能し、学習の必要性がはるかに少なくなります(そろばんは、位置計算機よりも作成と使用がはるかに簡単です!)。

このような割り当てでは、インタビュアーが実際に期待していることについて多くのヒットとミスがあります。多分彼らはあなたの思考プロセスを見たいだけです。技術を採用していますか(実際には乗算で<<はありませ)?あなたは数論とコンピュータサイエンスを知っていますか?あなたはあなたのコードを思い切って突っ込みますか、それとも説明を求めますか?あなたはそれを楽しい挑戦だと思いますか、それともあなたの仕事とは何の関連性もない、もう一つのとんでもない退屈なインタビューの質問だと思いますか?インタビュアーが探していた答えをあなたに伝えることは不可能です。

しかし、私は少なくともあなたに可能な答えを垣間見させてくれれば幸いです:)


ローマ数字システムを使用している場合、ローマ数字システムの一部ではないB、T、S、R、G、Aなどの文字がある場合、どのように追加しますか。言い換えれば、どのようにしてintに相当するのでしょうか?
Adheesh

@Adheesh私はあなたが何を尋ねようとしているのか分かりません。問題と思われるものの例を挙げていただけますか?
Luaan

文字列「12345」があり、それをintに変換したいとします。位置数値システムを使用せず、代わりにローマ数字システムを使用する場合はどうなりますか?どうすればできますか?(私は乗算をまったく使用したくない)
Adheesh

@Adheeshローマ数字システムでは、文字列は「12345」にはなりません。それがポイントです。位置数値システムは本質的に乗法的です。ローマ数字システムは加法的です。ローマ字列は「MMMMMMMMMMMMCCCXXXXIIIII」のようなものです。文字ごとに移動し、数字を追加していきます。
Luaan

@Adheeshもちろん、実際の現実では、それほど長く扱いにくい混乱にはなりません。「12345メートル」の代わりに、「XIIキロとCCCXXXXIIIIIメートル」などのように言います。古い測定システムは、あまり数えることができない人々に適応されました
-12

5

それはインタビューの質問であることを考えると、パフォーマンスは優先度が高くない場合があります。なぜだけではないのですか?

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

渡された文字列が整数でない場合、メソッドはオーバーフロー例外をスローします。


1
ブリリアント:Pインタビュアーからすぐにフィードバックがない場合は、使用しないことを確認してください。ただし、同じ基本的なアプローチを使用して、部分一致でパフォーマンスを改善する方法があるかもしれないと想像してください。少なくとも、負の数をチェックするだけでループの半分を節約できます。奇数/偶数のもう半分のチェック。
Luaan

@Luaan私はできる限り短い行でそれをやりたかった:) ...public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
nl-x

悲しいことに、それは爆発します:Dしかし、それは紙にコードを書くための素晴らしい解決策です-それはそれを非常に明らかに正しくし、間違って書くのは難しいです。LIINQ-を使用することもできますEnumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue
Luaan

0

乗算は繰り返し加算で置き換えることができます。そのため、既存のアルゴリズムの乗算を、加算のみを使用するバージョンに置き換えることができます。

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

さらに進んで、追加の数を最小限に抑えるこのアイデアを使用して、Intに特殊な文字列を書き込むことができます(簡潔にするために負の数とエラー処理は省略されています)。

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

しかし、パフォーマンスはここでは問題にならないと思われるので、それは問題に値するものではないと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.