乗算を使用せずに文字列を整数に変換する方法はありますか?int.Parse()の実装も乗算を使用します。文字列をintに手動で変換できる他の同様の質問がありますが、これには、その基数10で数値を乗算する必要があります。これは、インタビューの1つで受けたインタビューの質問であり、これに関する答えを見つけることができません。
for (int i = 0; i < 10; i++) result += number;
カウントしますか?
乗算を使用せずに文字列を整数に変換する方法はありますか?int.Parse()の実装も乗算を使用します。文字列をintに手動で変換できる他の同様の質問がありますが、これには、その基数10で数値を乗算する必要があります。これは、インタビューの1つで受けたインタビューの質問であり、これに関する答えを見つけることができません。
for (int i = 0; i < 10; i++) result += number;
カウントしますか?
回答:
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チェック、その他の非数値文字の問題などのエラーを考慮する必要があります。
場合によります。乗算の論理演算について話しているのか、それとも実際にハードウェアでそれを行うのか?
たとえば、16進数(または8進数、またはその他の2乗法)文字列を「乗算なし」の整数に変換できます。文字ごとに移動して、oring(|
)とbitshifting()を続けることができ<<
ます。これにより、*
演算子の使用が回避されます。
10進文字列で同じことを行うのは難しいですが、単純な追加がまだあります。ループを追加で使用して同じことを行うことができます。とても簡単です。または、独自の「乗算表」を作成することもできます。うまくいけば、学校で数値を乗算する方法を学びました。コンピュータでも同じことができます。もちろん、(バイナリではなく)10進数のコンピュータを使用している場合は、以前の16進数文字列と同じように「ビットシフト」を実行できます。バイナリコンピュータでも、一連のビットシフトを使用できます。これ(a << 1) + (a << 3)
はと同じa * 2 + a * 8 == a * 10
です。負の数に注意してください。あなたはこれを面白くするためにたくさんのトリックを理解することができます。
もちろん、これらはどちらも変装しただけの乗算です。これは、位置数値システムが本質的に乗法であるためです。これが、特定の数値表現が機能する方法です。この事実を隠す簡略化を行うことができます(たとえば、2進数では0
and のみが必要な1
ので、乗算する代わりに、単純な条件を設定できます。もちろん、実際に実行しているのは、まだ2つの入力と2つの可能性があるだけの乗算です。出力)、しかしそれは常にそこにあり、潜んでいます。操作を実行するハードウェアがより単純または高速である場合でも、はと<<
同じ* 2
です。
乗算を完全になくすには、位置システムの使用を避ける必要があります。例えば、ローマ数字は加法的である(実際のローマ数字は、我々が今日持っているコンパクト化ルールを使用していないことに注意してください- 4は次のようになりIIII
、ないIV
、それ14のような任意の形式で書くことができXIIII
、IIIIX
、IIXII
、VVIIII
など)。そのような文字列を整数に変換することは非常に簡単になります-文字ごとに行き、追加し続けるだけです。文字がの場合、X
10を追加します。の場合V
、5を追加します。もしI
、1つ追加します。なぜローマ数字がそれほど長い間人気を保っていたのか、理解していただければと思います。位置数値システムは、多くの乗算と除算を実行する必要がある場合に最適です。主に足し算と引き算を扱う場合、ローマ数字はうまく機能し、学習の必要性がはるかに少なくなります(そろばんは、位置計算機よりも作成と使用がはるかに簡単です!)。
このような割り当てでは、インタビュアーが実際に期待していることについて多くのヒットとミスがあります。多分彼らはあなたの思考プロセスを見たいだけです。技術を採用していますか(実際には乗算で<<
はありません)?あなたは数論とコンピュータサイエンスを知っていますか?あなたはあなたのコードを思い切って突っ込みますか、それとも説明を求めますか?あなたはそれを楽しい挑戦だと思いますか、それともあなたの仕事とは何の関連性もない、もう一つのとんでもない退屈なインタビューの質問だと思いますか?インタビュアーが探していた答えをあなたに伝えることは不可能です。
しかし、私は少なくともあなたに可能な答えを垣間見させてくれれば幸いです:)
それはインタビューの質問であることを考えると、パフォーマンスは優先度が高くない場合があります。なぜだけではないのですか?
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.
}
渡された文字列が整数でない場合、メソッドはオーバーフロー例外をスローします。
public int StringToInt(string value, int search_from = int.MinValue) => value == search_from.ToString() ? search_from : StringToInt (value, ++search_from);
Enumerable.Range(int.MinValue, int.MaxValue).First(i => i.ToString() == stringValue
。
乗算は繰り返し加算で置き換えることができます。そのため、既存のアルゴリズムの乗算を、加算のみを使用するバージョンに置き換えることができます。
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;
}
しかし、パフォーマンスはここでは問題にならないと思われるので、それは問題に値するものではないと思います。