大数类

来源:互联网 发布:iphone5s联通4g网络 编辑:程序博客网 时间:2024/05/01 18:12

虽然好多人写过了,但有段时间实在没事干,想着把以前写过基于string一个个bit计算的给改改。

基本功能都有,有一些简单测试,但不保证无bug

h文件:

#pragma once#include <exception>#include <string>using namespace std;class BiException : public std::exception{public:BiException(const char* msg): exception(msg){}};class BigInteger{int m_bit[200];bool m_sig;int m_high;int m_base;int m_low;const static int max_number = 10000;friend struct SigTemp;private:struct SigTemp {SigTemp(const BigInteger& bi);~SigTemp();BigInteger* p;};private:void set(__int64 n);bool set(const string& str);BigInteger abs_add(const BigInteger& bi) const;BigInteger abs_sub(const BigInteger& bi) const;BigInteger add(const BigInteger& bi) const;BigInteger sub(const BigInteger& bi) const;BigInteger& shift(int i);BigInteger mul(int n) const;BigInteger mul(const BigInteger& bi) const;int trydiv(const BigInteger& bi);BigInteger _div(const BigInteger& bi, bool mod, bool print = false) const;BigInteger div(const BigInteger& bi, bool print = false) const;BigInteger mod(const BigInteger& bi, bool print = false) const;int compare(const BigInteger& rhs) const;int abs_compare(const BigInteger& rhs) const;public:int length() const { return m_high - m_low; }public:BigInteger(__int64 n = 0);BigInteger(const string& str);BigInteger& operator = (__int64 n);BigInteger& operator = (const string& str);string tostring() const;BigInteger set_sig(bool minus = true) ;BigInteger& operator += (const BigInteger& rhs);BigInteger& operator -= (const BigInteger& rhs);BigInteger& operator *= (const BigInteger& rhs);BigInteger& operator /= (const BigInteger& rhs);BigInteger& operator %= (const BigInteger& rhs);BigInteger& operator -();#define MARCO_OP(ret, op) friend ret operator op (const BigInteger& lhs, const BigInteger& rhs)MARCO_OP(BigInteger, +);MARCO_OP(BigInteger, -);MARCO_OP(BigInteger, *);MARCO_OP(BigInteger, /);MARCO_OP(BigInteger, %);MARCO_OP(bool, <);MARCO_OP(bool, <=);MARCO_OP(bool, >);MARCO_OP(bool, >=);MARCO_OP(bool, ==);MARCO_OP(bool, !=);#undef MARCO_OPfriend ostream& operator <<(ostream& o, const BigInteger& bi);friend void test_biginteger();};inline BigInteger operator + (const BigInteger& lhs, const BigInteger& rhs){return lhs.add(rhs);}inline BigInteger operator - (const BigInteger& lhs, const BigInteger& rhs){return lhs.sub(rhs);}inline BigInteger operator * (const BigInteger& lhs, const BigInteger& rhs){return lhs.mul(rhs);}inline BigInteger operator / (const BigInteger& lhs, const BigInteger& rhs){return lhs.div(rhs);}inline BigInteger operator % (const BigInteger& lhs, const BigInteger& rhs){return lhs.mod(rhs);}inline ostream& operator <<(ostream& o, const BigInteger& bi){o<<bi.tostring();return o;}inline bool operator < (const BigInteger& lhs, const BigInteger& rhs){return lhs.compare(rhs) < 0;}inline bool operator <= (const BigInteger& lhs, const BigInteger& rhs){return lhs.compare(rhs) <= 0;}inline bool operator > (const BigInteger& lhs, const BigInteger& rhs){return lhs.compare(rhs) > 0;}inline bool operator >= (const BigInteger& lhs, const BigInteger& rhs){return lhs.compare(rhs) >= 0;}inline bool operator == (const BigInteger& lhs, const BigInteger& rhs){return lhs.compare(rhs) == 0;}inline bool operator != (const BigInteger& lhs, const BigInteger& rhs){return lhs.compare(rhs) != 0;}inline BigInteger makeint64(const BigInteger& high, const BigInteger& low){return (high * (BigInteger((__int64)1 << 32))) + low;}void test_biginteger();


cpp文件


#include "StdAfx.h"#include "BigInteger.h"#include <assert.h>//////////////////////////////////////////////////////////////////////////BigInteger::SigTemp::SigTemp(const BigInteger& bi): p(NULL){if(bi.m_sig) return;p = const_cast<BigInteger*>(&bi);p->set_sig(false);}BigInteger::SigTemp::~SigTemp(){if(p) p->set_sig(true);}//////////////////////////////////////////////////////////////////////////BigInteger::BigInteger(__int64 n){set(n);}BigInteger::BigInteger(const string& str){set(str);}BigInteger& BigInteger::operator = (__int64 n){set(n);return *this;}BigInteger& BigInteger::operator = (const string& str){set(str);return *this;}string BigInteger::tostring() const{string ret = m_sig ? "" : "-";char buf[8];for(int i = m_high - 1 ; i >= m_low ; -- i){sprintf(buf, (i == m_high - 1)? "%d" : "%04d", m_bit[i]);ret += buf;}return ret.empty() ? "0" : ret;}BigInteger BigInteger::set_sig(bool minus) { m_sig = !minus;return *this;}BigInteger& BigInteger::operator += (const BigInteger& rhs){return (*this = add(rhs));}BigInteger& BigInteger::operator -= (const BigInteger& rhs){return (*this = sub(rhs));}BigInteger& BigInteger::operator *= (const BigInteger& rhs){return (*this = mul(rhs));}BigInteger& BigInteger::operator /= (const BigInteger& rhs){return (*this = div(rhs));}BigInteger& BigInteger::operator %= (const BigInteger& rhs){return (*this = mod(rhs));}BigInteger& BigInteger::operator -(){m_sig = !m_sig;return *this;}void BigInteger::set(__int64 n){memset(this, 0, sizeof(BigInteger));m_sig = n >= 0;m_low = m_high = m_base = 100;__int64 carry = n < 0 ? -n : n;int i = m_base;for( ; carry ; ++ i){m_bit[i] = carry % (__int64)max_number;carry /= (__int64)max_number;}if(i > m_high) m_high = i;}bool BigInteger::set(const string& str){int len = str.length();if(len == 0) return false;memset(this, 0, sizeof(BigInteger));m_low = m_high = m_base = 100;m_sig = (str[0] != '-');int low = m_sig ? 0 : 1, tmp = 0, bit = 1, i = m_base, j = len - 1;for( ; ; -- j){if(!isdigit(str[j])) return false;tmp += bit * (str[j] - '0');bit *= 10;if(j == low) {m_bit[i++] = tmp;break;}if(tmp > max_number / 10){m_bit[i++] = tmp;bit = 1;tmp = 0;}}if(i > m_high) m_high = i;return true;}BigInteger BigInteger::abs_add(const BigInteger& bi) const{if(bi.length() == 0) return *this;BigInteger result(*this);int i = result.m_low, j = bi.m_low, carry = 0, tmp = 0;do{tmp = carry + result.m_bit[i] + bi.m_bit[j];result.m_bit[i] = tmp % max_number;carry = tmp / max_number;++i,++j;}while(i < result.m_high || j < bi.m_high || carry);if(i > result.m_high) result.m_high = i;return result;}BigInteger BigInteger::abs_sub(const BigInteger& bi) const{if(bi.length() == 0) return *this;BigInteger result(*this);int i = result.m_low, j = bi.m_low, carry = 0, tmp = 0, zerobit = result.m_low, nonzerobit = result.m_low;do{tmp = carry + result.m_bit[i] - bi.m_bit[j];carry = 0;if(tmp == 0){zerobit = i;}else{nonzerobit = i;if(tmp < 0) {tmp += max_number;carry = -1;}}result.m_bit[i] = tmp;++i,++j;}while((i < result.m_high && j < bi.m_high) || carry);if(i == result.m_high && zerobit > nonzerobit) result.m_high = nonzerobit + 1;return result;}BigInteger BigInteger::add(const BigInteger& bi) const{if(bi.length() == 0) return *this;if(m_sig != bi.m_sig){BigInteger result;int ret = abs_compare(bi);if(ret == 0) return result;if(ret == -1) {result = bi.sub(*this);if(m_sig) result.m_sig = false;}else{result = sub(bi);if(!m_sig) result.m_sig = false;}return result; }return abs_add(bi);}BigInteger BigInteger::sub(const BigInteger& bi) const{if(bi.length() == 0) return *this;if(m_sig) // +{// -if(!bi.m_sig) return abs_add(bi);// +int ret = abs_compare(bi);if(ret < 0) return bi.abs_sub(*this).set_sig();if(ret == 0) return 0;return abs_sub(bi);}// -// +if(bi.m_sig) return abs_add(bi);// -int ret = abs_compare(bi);if(ret < 0) return bi.abs_sub(*this).set_sig(false);if(ret == 0) return 0;return abs_sub(bi);}BigInteger& BigInteger::shift(int i){if(length() == 0) return *this;m_low -= i;return *this;}BigInteger BigInteger::mul(int n) const{if(n == 0) return BigInteger(0);BigInteger result(*this);int i = result.m_base, carry = 0, tmp = 0;while((tmp = result.m_bit[i] * n + carry) || i < result.m_high) {result.m_bit[i] = tmp % max_number;carry = tmp / max_number;++i;}if(i > result.m_high) result.m_high = i;return result;}BigInteger BigInteger::mul(const BigInteger& bi) const{BigInteger result;if(bi.m_high - bi.m_low == 0) return result;bool sig = !(m_sig ^ bi.m_sig);SigTemp o(bi);for(int i = bi.m_base ; i < bi.m_high ; ++ i){result += (mul(bi.m_bit[i]).shift(i - bi.m_base));}result.m_sig = sig;return result;}int BigInteger::trydiv(const BigInteger& bi){assert(abs_compare(bi) >= 0);int l = 1, h = 9999, c = h - l + 1, comp = 0;while(c){int c2 = c / 2;int mid = l + c2;comp = abs_compare(bi.mul(mid));if(comp < 0){c = c2;}else if(comp > 0){l = mid + 1;c = c2 - 1;}elsereturn mid;}BigInteger tmp = bi.mul(l);int ret = abs_compare(tmp);if(ret > 0){while(abs_compare(tmp += bi) >= 0 && ++ l);return l;}else{while(-- l && abs_compare(tmp -= bi) <= 0);return l;}return l;}BigInteger BigInteger::_div(const BigInteger& bi, bool mod, bool print) const{if(bi.abs_compare(0) == 0) throw BiException("Div by zero!");if(abs_compare(0) == 0) return BigInteger(0);int ret = abs_compare(bi);if(ret < 0) return BigInteger(0);if(ret == 0) return BigInteger(!(m_sig ^ bi.m_sig));bool sig = !(m_sig ^ bi.m_sig);SigTemp o(bi);BigInteger tmp, result;for(int i = m_high - 1 ; i >= m_base ; -- i){tmp.shift(1) += m_bit[i];int ret = tmp.abs_compare(bi);if(ret == -1){if(i != m_high - 1){result.shift(1);}continue;}if(ret == 0){result = result.shift(1).add(1);tmp.set(0);}else{int trydiv = tmp.trydiv(bi);if(print){printf("%s trydiv %s, 商 = %d",tmp.tostring().c_str(), bi.tostring().c_str(), trydiv);}result = result.shift(1).add(trydiv);tmp -= bi.mul(trydiv);if(print)printf("余数 = %s\n", tmp.tostring().c_str());}}if(!mod)result.m_sig = sig;return mod ? tmp : result;}BigInteger BigInteger::div(const BigInteger& bi, bool print) const{return _div(bi, false, print);}BigInteger BigInteger::mod(const BigInteger& bi, bool print) const{return _div(bi, true, print);}int BigInteger::compare(const BigInteger& rhs) const{if(m_sig != rhs.m_sig) return (int)m_sig - (int)rhs.m_sig;return abs_compare(rhs);}int BigInteger::abs_compare(const BigInteger& rhs) const{int l1 = length(), l2 = rhs.length();if(l1 != l2) return l1 < l2 ? -1 : 1;for(int i = m_high - 1, j = rhs.m_high - 1 ; i >= m_low ; -- i, -- j){if(m_bit[i] != rhs.m_bit[j]) return m_bit[i] < rhs.m_bit[j] ? -1 : 1;}return 0;}//test//////////////////////////////////////////////////////////////////////////#define MAKE_INT64(h, l) (__int64)((l) | ((__int64)h << 32))#include <iostream>#include <time.h>#include <windows.h>using namespace std;void test_biginteger(){#if 0BigInteger b1(-32889549839), b2(-9839);cout<<b2-b1<<endl;return;#endifsrand((unsigned int)time(0));BigInteger bi1, bi2, bi3, bi4;DWORD t = GetTickCount();for(int i = 0 ; i < 100000 ; ++ i){int l = rand(),h = rand();__int64 x = MAKE_INT64(h, l);bi1 = l, bi2 = h;bi3 = makeint64(h, l);if(!(bi3.compare(x) == 0))printf("error\n");l = rand(), h = rand();__int64 y = (__int64)l * (__int64)h;bi1 = l, bi2 = h;bi4 = bi1 * bi2;if(!(bi4.compare(y) == 0))printf("error\n");if(rand() & 1){bi4.set_sig();y = -y;}if(rand() & 1){bi3.set_sig();x = -x;}int t = 2;//rand() % 3;switch(t){case 0:{if((bi4 + bi3).compare(x + y) != 0)printf("error\n");}break;case 1:{if((bi4 - bi3).compare(y - x) != 0)printf("error\n");}break;case 2:{if(bi4.compare(bi3) > 0){if(x == 0) continue;if((bi4 / bi3).compare(y / x) != 0){printf("error\n");bi4.div(bi3, true);cout<<bi4<<" / "<<bi3<<" : ";cout<<"shoule be "<< y/x<<", infact = "<<(bi4/bi3).tostring()<<endl;int a = 1;}}else{if(y == 0) continue;if((bi3 / bi4).compare(x / y) != 0){printf("error\n");bi3.div(bi4, true);cout<<bi3<<" / "<<bi4<<" : ";cout<<"shoule be "<< x/y<<", infact = "<<(bi3/bi4).tostring()<<endl;int a = 1;}}}break;default:break;}}cout<<__FUNCTION__<<" cost "<<GetTickCount() - t<<" ms.\n";}



0 0