楽しい挑戦。:)
任意の長さの整数が必要だと思います。次のアプローチをお勧めします。
データ型「int」のバイナリの性質を考慮してください。単純な二項演算を使用して、CPU内の回路が何かを追加するときに何をするかをエミュレートすることを検討してください。より詳細に関心がある場合は、半加算器と全加算器に関するこのウィキペディアの記事を読むことを検討してください。あなたはそれに似た何かをするでしょう、しかしあなたはそれと同じくらい低いレベルに下がることができます-しかし怠惰なので、私はただ見捨てて、もっと簡単な解決策を見つけるだろうと思いました。
しかし、加算、減算、乗算に関するアルゴリズムの詳細に入る前に、いくつかのデータ構造を見つけましょう。もちろん、簡単な方法は、std :: vectorに物事を保存することです。
template< class BaseType >
class BigInt
{
typedef typename BaseType BT;
protected: std::vector< BaseType > value_;
};
固定サイズのベクトルを作成するかどうか、および事前に割り当てるかどうかを検討することをお勧めします。理由は、さまざまな操作の場合、ベクトルの各要素(O(n))を通過する必要があるためです。操作がどれほど複雑になるかを直接知りたいと思うかもしれませんが、固定nはまさにそれを行います。
しかし、ここで、数値の操作に関するいくつかのアルゴリズムについて説明します。ロジックレベルでそれを行うこともできますが、その魔法のCPUパワーを使用して結果を計算します。しかし、HalfAddersとFullAddersのロジック図から引き継ぐのは、キャリーの処理方法です。例として、+ =演算子をどのように実装するかを考えてみましょう。BigInt <> :: value_の数値ごとに、それらを追加して、結果が何らかの形のキャリーを生成するかどうかを確認します。ビット単位では実行しませんが、BaseTypeの性質(long、int、shortなど)に依存します。オーバーフローします。
確かに、2つの数値を加算すると、結果はそれらの数値の大きい方よりも大きくなるはずですよね?そうでない場合、結果はオーバーフローしました。
template< class BaseType >
BigInt< BaseType >& BigInt< BaseType >::operator += (BigInt< BaseType > const& operand)
{
BT count, carry = 0;
for (count = 0; count < std::max(value_.size(), operand.value_.size(); count++)
{
BT op0 = count < value_.size() ? value_.at(count) : 0,
op1 = count < operand.value_.size() ? operand.value_.at(count) : 0;
BT digits_result = op0 + op1 + carry;
if (digits_result-carry < std::max(op0, op1)
{
BT carry_old = carry;
carry = digits_result;
digits_result = (op0 + op1 + carry) >> sizeof(BT)*8;
}
else carry = 0;
}
return *this;
}
他の算術演算も同様です。stl-functors std :: plusとstd :: minus、std :: times、std :: dividesなどを使用することもできますがキャリーに注意してください。:)プラス演算子とマイナス演算子を使用して乗算と除算を実装することもできますが、各反復でプラスとマイナスを以前に呼び出したときにすでに計算した結果が再計算されるため、非常に時間がかかります。この単純なタスクには、ウィキペディアまたはWebを使用する ための優れたアルゴリズムがたくさんあります。
そしてもちろん、次のような標準演算子を実装する必要がありますoperator<<
(value_の各値をnビット左にシフトしvalue_.size()-1
ます...ああ、キャリーを覚えておいてoperator<
ください:)-ここで少し最適化して、size()
最初の大まかな桁数。等々。次に、befriendig std :: ostreamを使用して、クラスを便利にしますoperator<<
。
このアプローチがお役に立てば幸いです。