///============================================================================ // // multi integer // // tkuri {at} fat.coara.or.jp // #ifndef mint_hpp_ #define mint_hpp_ #define MINT_ASSERTION_FAILED_EXCEPTION() "assertion failed" #define MINT_ZERO_DIVIDE_EXCEPTION() "zero divide" //============================================================================= template< int N = 2 > struct MultiInteger { typedef MultiInteger Ty; // このクラスが認知している "符号なし整数" の型 typedef unsigned int uint; enum { UINT_BITS = 32, // uint のビット数 NUMBER = N, // いくつの int 配列か BITS = N * UINT_BITS }; // 全体で何ビットになるか static void mintAssert (bool cond, const char *msg) { if (!cond) throw MINT_ASSERTION_FAILED_EXCEPTION(); } uint factor_[N]; //! コンストラクタ MultiInteger () { beZero(); } //! コンストラクタ explicit MultiInteger (uint i) { beZero(); factor_[0] = i; } //! コンストラクタ -- 文字列を受け取る explicit MultiInteger (const char *str) { *this = str; } //! コピーコンストラクタ MultiInteger (const Ty& di) { for (int n=0; n>= ( -i ); if (i >= Ty::BITS) { beZero(); return *this; } int n, distance = i / UINT_BITS, shift = i & (UINT_BITS-1); for (n=N-1; n>distance; --n) { factor_[ n ] = factor_[n - distance] << shift; if (shift) factor_[ n ] |= factor_[n - distance - 1] >> (UINT_BITS - shift); } factor_[distance] = factor_[0] << shift; for (n=distance-1; n>=0; --n) factor_[n] = 0; return *this; } //! 左シフト Ty operator << ( int i ) const { Ty temp = *this; temp <<= i; return temp; } //! 右シフト Ty& operator >>= ( int i ) { if (i == 0) return *this; if (i < 0) return operator <<= ( -i ); if (i >= Ty::BITS) { beZero(); return *this; } int n, distance = i / UINT_BITS, shift = i & (UINT_BITS-1); for (n = 0; n < N-1-distance; ++n) { factor_[ n ] = factor_[ n + distance ] >> shift; if (shift) factor_[ n ] |= factor_[ n + distance + 1 ] << (UINT_BITS - shift); } factor_[N-1 - distance] = factor_[N-1] >> shift; for (n = N - distance; n < N; ++n) factor_[n] = 0; return *this; } //! 右シフト Ty operator >> ( int i ) const { Ty temp = *this; temp >>= i; return temp; } //! not Ty operator ~ () const { Ty temp = *this; temp.negate(); return temp; } //! インクリメント Ty& operator ++ () { ++factor_[0]; for (int n=1; n < N; ++n) if (factor_[n - 1] == (uint)0) ++factor_[n]; else break; return *this; } //! 後置インクリメント Ty operator ++ (int) { Ty temp(*this); ++(*this); return temp; } //! デクリメント Ty& operator -- () { for (int n=0; n0 .. this > di int compare (const Ty& di) const { if (this == &di) return 0; for (int n=N-1; n >= 0; --n) { if (factor_[n] < di.factor_[n]) return -1; if (factor_[n] > di.factor_[n]) return 1; } return 0; } //! uint と比較演算 int compare (uint i) const { for (int n=N-1; n > 0; --n) if (factor_[n]) return 1; if (factor_[0] < i) return -1; if (factor_[0] > i) return 1; return 0; } /*! src / di を実行し,result に格納 * result に商,src に余りが残る * result は省略可能 */ static Ty& divide_process ( Ty *src, const Ty& di, Ty *result = 0 ) { if (di.isZero()) throw MINT_ZERO_DIVIDE_EXCEPTION(); if (*src < di) { if (result) result->beZero(); return *src; } // ここで 0 < di <= *src が確定 if (src == &di || *src == di) { if (result) result->raiseBit(0); // result = 1; src->beZero(); return *src; } mintAssert(Ty((uint)0) < di && di < *src, "error at divide_process (A)"); // だからここで di は 1 以上,src は 2 以上であるはず Ty temp = di; int n = N-1, p1=Ty::BITS-1, p2; // 大まかに,MSB から最初にビットが立っている箇所を見つける while (src->factor_[n] == 0) { mintAssert(n > 0, "error at divide_process (B)"); --n; p1 -= UINT_BITS; } p2 = p1; while (temp.factor_[n] == 0) { mintAssert(n > 0, "error at divide_process (C)"); --n; p2 -= UINT_BITS; } // MSB から最初に立っているビットを見つける while (src->getBit( p1 ) == 0) { mintAssert(p1 > 1, "error at divide_process (D)"); --p1; } if (p2 > p1) p2 = p1; while (temp.getBit( p2 ) == 0) { mintAssert(p2 > 0, "error at divide_process (E)"); --p2; } int i = p1 - p2; temp <<= i; do { while (*src < temp) { --i; temp >>= 1; } *src -= temp; if (result) result->raiseBit( i ); } while (*src >= di); return *src; } //! モジュロ演算 Ty& operator %= (const Ty& di ) { divide_process( this, di ); return *this; } //! uint とのモジュロ Ty& operator %= (uint i) { divide_process( this, (Ty)i ); return *this; } //! 除算 Ty& operator /= (const Ty& di ) { Ty result; divide_process( this, di, &result ); *this = result; return *this; } //! uint との除算 Ty& operator /= (uint i) { return ((*this) /= (Ty)i); } //! 乗算 Ty& operator *= ( const Ty& di ) { if (this == &di) { Ty copy(di); return operator *= (copy); } Ty temp(*this); beZero(); int prev_n = 0; for (int n=0; n < Ty::BITS; ++n) { if (di.getBit( n )) { temp <<= (n - prev_n); *this += temp; prev_n = n; } } return *this; } //! uint との乗算 Ty& operator *= ( uint i ) { Ty temp(*this); beZero(); int prev_n = 0; for (int n = 0; n < UINT_BITS; ++n) { if (i & (1 << n)) { temp <<= (n - prev_n); *this += temp; prev_n = n; } } return *this; } //! uint 型へのキャスト // mint = mint + 1; のようなコードが通らないからだめ! // (builtin function operator + (uint, int)) //operator uint () const { // return factor_[0]; //} //! if ステートメントなどの 否定 bool operator ! () const { return isZero(); } //! if ステートメントなど operator const void * () const { if (isZero()) return 0; return static_cast(this); } #if 1 //! uint 型を代入 Ty& operator = (uint i) { beZero(); factor_[0] = i; return *this; } #else // ↓はジョーク /*! 数値を受け取る * * 普通に代入 * MultiInteger<2> mint; * mint = 12345; * * 大きな数値はコンマ区切りで * MultiInteger<2> mint_big; * mint_big = 1,123,456,789,102,345,678,901,234; * * 現在の問題点 : コンマ区切りの場合,こんなのは期待通りの動きをしない * MultiInteger<2> mint_big; * mint_big = 12,012; // コンマの直後が 0 ... '012' の部分が8進数と見なされる * * コンマの位置をずらせばいいけど,汚いかも? * MultiInteger<2> mint_big: * mint_big = 120,12; */ class CommaEater { //typedef unsigned int uint; public: explicit CommaEater ( MultiInteger& self ) : self_(self) {} CommaEater operator , ( uint i ) { self_ *= get_unit(i); self_ += i; return *this; } operator MultiInteger& () { return self_; } private: MultiInteger& self_; uint get_unit (uint i) { uint r = 1; do { r *= 10; i /= 10; } while(i); return r; } }; CommaEater operator = (uint i) { CommaEater com(*this); beZero(); com , i; return com; } #endif // ジョーク終わり /*! C文字列を代入 * "1,948,454,654,523_278_523_156" .. コンマやアンダーバー で区切ってもよい * "0x_520A_Df99_8bc3_14aD" .. 大文字小文字交じりの 16進数 (プレフィクスは 0x) * "0b_10010111_11001011" .. 2進数 * "0o_144_457_243_155" .. 8 進数 * "0_234143543" .. 先頭がゼロなのも 8 進数 * "aaa12345" .. 文字列の先頭が数値でなければ,数値が見つかるまでスキップされる * 先頭の a は 16 進数のとは解釈されず,スキップされる * よってこれは 10 進 12345 となる * "0x0H00" .. 途中で,現在認知している基数ではありえない文字があれば * そこで解析は終了 .. この文字列は 16進数 0 となる * * @param str .. 文字列へのポインタ。 * @param len .. 文字列の長さ。省略するかマイナスを入力すると,str が nil 終端だと仮定する。 * * @returns *this .. 自分自身を返す */ #define mintBIN( _c ) (_c == '0' || _c == '1') #define mintOCT( _c ) ('0' <= _c && _c <= '7') #define mintDEC( _c ) ('0' <= _c && _c <= '9') #define mintHEX( _c ) (mintDEC(_c) || ('a'<=(_c|0x20) && (_c|0x20)<='f')) Ty& assignCStr (const char *str, int len = -1 ) { if (len < 0) len = 0x7fffffff; // 適当に大きな数を。\0 を見つけたら自然に解析終了。 int p = 0; uint base = 10, denomi = 100000000; beZero(); if (!str) return *this; while (p= UINT_BITS) ++n, pos -= UINT_BITS; if (n < N) factor_[n] |= 1 << pos; } //! pos ビット目を 0 にする void dropBit (unsigned int pos) { unsigned int n = 0; while (pos >= UINT_BITS) ++n, pos -= UINT_BITS; if (n < N) factor_[n] &= ~(1 << pos); } //! pos ビット目を反転させる void flipBit (unsigned int pos) { unsigned int n = 0; while (pos >= UINT_BITS) ++n, pos -= UINT_BITS; if (n < N) factor_[n] ^= 1 << pos; } //! pos ビット目を b (0 or 1) にする void setBit (unsigned int pos, int b) { if (b) raiseBit(pos); else dropBit(pos); } //! pos ビット目を得る int getBit (unsigned int pos) const { if (Ty::BITS <= pos) return 0; int n = 0; while (pos >= UINT_BITS) ++n, pos -= UINT_BITS; return (factor_[n] & (1 << pos)) ? 1 : 0; } //! c_str のためのユーティリティ char *_c_str (const Ty& self, char *result, unsigned int *size, uint base, unsigned int rlevel) const { if (self >= (Ty)base) { result = _c_str( self / base, result, size, base, rlevel + 1 ); } if (1 < *size) { if (*size <= rlevel && *size <= 4) { *result = '.'; } else { int i = (self % base).uint_value(); if (i < 10) *result = (char)i + '0'; else *result = (char)i + 'a' - 10; } --*size; ++result; } return result; } /*! Cタイプの文字列表現 * @param buf 文字列を格納するためのバッファ * @param size バッファに用意されているサイズ * @param base 基数 * * 桁が大きいと大量に再帰する。スタックあふれに注意 */ const char * c_str (char *buf, unsigned int size, uint base = 10) const { *_c_str( *this, buf, &size, base, 1 ) = 0; return buf; } /*! uint へのキャストの代わりに */ uint uint_value () const { return factor_[0]; } }; /* * c_str はスタックあふれに注意。 * 巨大な数字を持つ事が分かっているなら,分割して取得するべき。 * * 以下,そこそこ良さげな to_string の実装例。 template std::string to_string (const Mint& bignum) { std::string result; if (! bignum) result = "0"; else { const unsigned int denomi = 1000000000; // 適当に大きな 10^n の数 char buf[11]; std::string fragment; Mint temp1, temp2 = bignum; while (temp2) { temp1 = temp2 % denomi; fragment = temp1.c_str(buf, sizeof(buf)); result.insert(0, fragment); temp2 /= denomi; // ゼロサプレスするべき? if (temp2) { // assert (fragment.length() <= 9); result.insert(0, 9 - fragment.length(), '0'); // 9 は denomi の 0 の個数 } } } return result; } * * */ #define Mint MultiInteger #define Mint_uint typename MultiInteger::uint //! 加算 template Mint operator + (const Mint& lhs, const Mint& rhs) { Mint temp(lhs); return temp += rhs; } //! uint と加算 template Mint operator + (const Mint& lhs, Mint_uint rhs) { Mint temp(lhs); return temp += rhs; } //! uint と加算: ヒント: A + B == B + A template Mint operator + (Mint_uint lhs, const Mint& rhs) { Mint temp(rhs); return temp += lhs; } //! 減算 template Mint operator - (const Mint& lhs, const Mint& rhs) { Mint temp(lhs); return temp -= rhs; } //! uint を減算 template Mint operator - (const Mint& lhs, Mint_uint rhs) { Mint temp(lhs); return temp -= rhs; } //! uint から減算 template Mint operator - (Mint_uint lhs, const Mint& rhs) { Mint temp(lhs); return temp -= rhs; } //! 乗算 template Mint operator * (const Mint& lhs, const Mint& rhs) { Mint temp(lhs); return temp *= rhs; } //! uint と乗算 template Mint operator * (const Mint& lhs, Mint_uint rhs) { Mint temp(lhs); return temp *= rhs; } //! uint と乗算 ヒント:A * B == B * A template Mint operator * (Mint_uint lhs, const Mint& rhs) { Mint temp(rhs); return temp *= lhs; } //! 除算 template Mint operator / (const Mint& lhs, const Mint& rhs) { Mint temp(lhs); return temp /= rhs; } //! uint で除算 template Mint operator / (const Mint& lhs, Mint_uint rhs) { Mint temp(lhs); return temp /= rhs; } //! uint を除算 template Mint operator / (Mint_uint lhs, const Mint& rhs) { Mint temp(lhs); return temp /= rhs; } //! モジュロ template Mint operator % (const Mint& lhs, const Mint& rhs) { Mint temp(lhs); return temp %= rhs; } //! uint のモジュロ template Mint operator % (const Mint& lhs, Mint_uint rhs) { Mint temp(lhs); return temp %= rhs; } //! uint からモジュロをとる template Mint operator % (Mint_uint lhs, const Mint& rhs) { Mint temp(lhs); return temp %= rhs; } //! and 演算 template Mint operator & (const Mint& lhs, const Mint& rhs) { Mint temp(lhs); return temp &= rhs; } //! uint と and 演算 template Mint operator & (const Mint& lhs, Mint_uint rhs) { Mint temp(lhs); return temp &= rhs; } //! uint と and 演算 ヒント:A & B == B & A template Mint operator & (Mint_uint lhs, const Mint& rhs) { Mint temp(rhs); return temp &= lhs; } //! or 演算 template Mint operator | (const Mint& lhs, const Mint& rhs) { Mint temp(lhs); return temp |= rhs; } //! uint と or 演算 template Mint operator | (const Mint& lhs, Mint_uint rhs) { Mint temp(lhs); return temp |= rhs; } //! uint と or 演算 ヒント:A | B == B | A template Mint operator | (Mint_uint lhs, const Mint& rhs) { Mint temp(rhs); return temp |= lhs; } //! xor 演算 template Mint operator ^ (const Mint& lhs, const Mint& rhs) { Mint temp(lhs); return temp ^= rhs; } //! uint と xor 演算 template Mint operator ^ (const Mint& lhs, Mint_uint rhs) { Mint temp(lhs); return temp ^= rhs; } //! uint と xor 演算 ヒント:A ^ B == B ^ A template Mint operator ^ (Mint_uint lhs, const Mint& rhs) { Mint temp(rhs); return temp ^= lhs; } //! == 比較 template bool operator == (const Mint& lhs, const Mint& rhs) { return (lhs.compare(rhs) == 0); } //! uint と == 比較 template bool operator == (const Mint& lhs, Mint_uint rhs) { return (lhs.compare(rhs) == 0); } //! uint と == 比較 template bool operator == (Mint_uint lhs, const Mint& rhs) { return (rhs == lhs); } //! != 比較 template bool operator != (const Mint& lhs, const Mint& rhs) { return !(lhs == rhs); } //! uint と != 比較 template bool operator != (const Mint& lhs, Mint_uint rhs) { return !(lhs == rhs); } //! uint と != 比較 template bool operator != (Mint_uint lhs, const Mint& rhs) { return !(lhs == rhs); } //! < 比較 template bool operator < (const Mint& lhs, const Mint& rhs) { return (lhs.compare(rhs) < 0); } //! uint と < 比較 template bool operator < (const Mint& lhs, Mint_uint rhs) { return (lhs.compare(rhs) < 0); } //! uint と < 比較 template bool operator < (Mint_uint lhs, const Mint& rhs) { return (rhs.compare(lhs) > 0); } //! > 比較 template bool operator > (const Mint& lhs, const Mint& rhs) { return (lhs.compare(rhs) > 0); } //! uint と > 比較 template bool operator > (const Mint& lhs, Mint_uint rhs) { return (lhs.compare(rhs) > 0); } //! uint と > 比較 template bool operator > (Mint_uint lhs, const Mint& rhs) { return (rhs.compare(lhs) < 0); } //! <= 比較 template bool operator <= (const Mint& lhs, const Mint& rhs) { return !(lhs > rhs); } //! uint と <= 比較 template bool operator <= (const Mint& lhs, Mint_uint rhs) { return !(lhs > rhs); } //! uint と <= 比較 template bool operator <= (Mint_uint lhs, const Mint& rhs) { return !(lhs > rhs); } //! >= 比較 template bool operator >= (const Mint& lhs, const Mint& rhs) { return !(lhs < rhs); } //! uint と >= 比較 template bool operator >= (const Mint& lhs, Mint_uint rhs) { return !(lhs < rhs); } //! uint と >= 比較 template bool operator >= (Mint_uint lhs, const Mint& rhs) { return !(lhs < rhs); } #undef Mint_uint #undef Mint #undef MINT_ASSERTION_FAILED_EXCEPTION #undef MINT_ZERO_DIVIDE_EXCEPTION /* * 履歴 * 2004-09-17 * 参考コードの to_string() でゼロ詰めを忘れているバグ修正 (cppllの小野さんより指摘) * operator *= () で,同じインスタンスとの演算結果が 0 になるバグ修正。 * 外部の operator OP () を大量に追加して,クラス内のメソッドを整理。 * operator uint () は削除。代わりに uint_value() を追加。 * assignCStr() の引数 len は int 型なのに,それと比較する変数 p が * unsigned なのは気持ち悪いので変更,それに伴って見つかった,len の * デフォルト値設定のバグも修正。 * * 2004-09-16 * cppll で晒す。 * * 2004-いつだっけ * あやしいで晒す。 * 誰かがこのコードで就職に挑んで,職を勝ち取ったらしい。ずるい。 */ #endif // mint_hpp_