楽しいチャレンジ。:)
任意の長さの整数が必要だと思います。次のアプローチをお勧めします。
データ型「int」のバイナリの性質を考慮してください。単純な二項演算を使用して、CPU 内の回路が何かを追加するときに何をするかをエミュレートすることを考えてみてください。さらに詳しく知りたい場合は、半加算器と全加算器に関するこのウィキペディアの記事を読むことを検討してください。あなたはそれに似たようなことをしていますが、それと同じくらい低いレベルに行くこともできます.
しかし、加算、減算、乗算に関するアルゴリズムの詳細に入る前に、いくつかのデータ構造を見つけてみましょう。もちろん、簡単な方法は std::vector に格納することです。
template< class BaseType >
class BigInt
{
typedef typename BaseType BT;
protected: std::vector< BaseType > value_;
};
固定サイズのベクトルを作成するかどうか、およびそれを事前に割り当てるかどうかを検討することをお勧めします。その理由は、さまざまな操作のために、ベクトルの各要素 - O(n) を通過する必要があるからです。操作がどれほど複雑になるかを直接知りたい場合があり、固定 n はまさにそれを行います。
しかし、ここで、数値を操作するいくつかのアルゴリズムについて説明します。ロジック レベルで実行することもできますが、その魔法の CPU パワーを使用して結果を計算します。しかし、Half-Adders と 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; // NOTE [1]
}
else carry = 0;
}
return *this;
}
// NOTE 1: I did not test this code. And I am not sure if this will work; if it does
// not, then you must restrict BaseType to be the second biggest type
// available, i.e. a 32-bit int when you have a 64-bit long. Then use
// a temporary or a cast to the mightier type and retrieve the upper bits.
// Or you do it bitwise. ;-)
他の算術演算も同様です。一体、stl-functor std::plus と std::minus、std::times と std::divides を使用することもできますが、キャリーに注意してください。:) プラス演算子とマイナス演算子を使用して乗算と除算を実装することもできますが、それは非常に遅くなります。これは、反復ごとに以前のプラスとマイナスの呼び出しで既に計算した結果を再計算するためです。この単純なタスクには、ウィキペディアまたは Webを使用する ための優れたアルゴリズムがたくさんあります。
そしてもちろん、次のような標準演算子を実装する必要がありますoperator<<
(value_ の各値を左に n ビットシフトするだけvalue_.size()-1
です。... ああ、キャリーを覚えておいてoperator<
ください :)、-ここで少し最適化して、おおよその桁数をsize()
最初に付けます。等々。次に、 befriendig std::ostream によって、クラスを便利にしますoperator<<
。
このアプローチが役立つことを願っています!