
Эксперт
   
Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург
Репутация: 34 Всего: 59
|
Установил вожделенную 2009. Для начала скормил ей простенький старенький класс с тестом (практиковался в реализации большого целого). В шестерке компилится без вопросов, в 2009 выдает ошибку: не найден метод... короче E2285. Привожу коды целиком - может кто попробует откомпилить у себя на 2009 (может криво встала). Шестерка спокойно компилит и все работает. Заголовок: | Код | //---------------------------------------------------------------------------
#ifndef UTMAN_HugeIntH #define UTMAN_HugeIntH //--------------------------------------------------------------------------- class TMAN_HugeInt { private: unsigned char *Num; int Size; bool Negative; public: TMAN_HugeInt(TMAN_HugeInt& pSrc); TMAN_HugeInt(void); TMAN_HugeInt(TMAN_HugeInt *pSrc); ~TMAN_HugeInt(); char * ToBinStr(char * pBuffer); int GetBinStrSize(void) { return Size * 8 + 2; }; TMAN_HugeInt operator=(int pNum); TMAN_HugeInt operator=(TMAN_HugeInt pNum); TMAN_HugeInt operator+(TMAN_HugeInt pNum); TMAN_HugeInt operator-(TMAN_HugeInt pNum); TMAN_HugeInt operator<<(int pCount); TMAN_HugeInt operator>>(int pCount); TMAN_HugeInt operator>>=(int pCount); TMAN_HugeInt operator<<=(int pCount); TMAN_HugeInt operator*(TMAN_HugeInt pNum); TMAN_HugeInt operator/(TMAN_HugeInt pNum); TMAN_HugeInt operator/=(TMAN_HugeInt pNum); TMAN_HugeInt operator%(TMAN_HugeInt pNum); void ShiftLeft(int pCount); void ShiftRight(int pCount); void Add(TMAN_HugeInt & pNum); void Mul(TMAN_HugeInt pNum); bool IsZero(void); void SetZero(void); bool Less(TMAN_HugeInt pNum); bool Gross(TMAN_HugeInt pNum); bool Equ(TMAN_HugeInt pNum); void Sub(TMAN_HugeInt pNum); void Div(TMAN_HugeInt pDiv); int LengthBin(void); char* ToDecStr(char * pBuf); TMAN_HugeInt(int pNum); int ToInt(void); char* ToITStr(char * pBuf); };
bool operator<(TMAN_HugeInt pNum1,TMAN_HugeInt pNum2); bool operator>(TMAN_HugeInt pNum1,TMAN_HugeInt pNum2); bool operator==(TMAN_HugeInt pNum1,TMAN_HugeInt pNum2); bool operator!=(TMAN_HugeInt pNum1,TMAN_HugeInt pNum2);
#endif
|
Сам код: | Код | //--------------------------------------------------------------------------- /* Класс огромного целого По умолчанию - 100 байт (int800) */ #include <mem.h> #include <system.hpp> #include <Sysutils.hpp> #include <math> #pragma hdrstop
#define TMAN_HUGE_INT_SIZE 100 #include "UTMAN_HugeInt.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//--------------------------------------------------------------------------- /* Конструктор без параметров. Создает число размерностью 100 байт */ TMAN_HugeInt::TMAN_HugeInt(void) { Size = TMAN_HUGE_INT_SIZE; Num = new unsigned char[Size]; SetZero(); }
//--------------------------------------------------------------------------- /* Конструктор c параметром - принимает указатель на такой же объект Создает число размерностью 100 байт */ TMAN_HugeInt::TMAN_HugeInt(TMAN_HugeInt *pSrc) { Size = pSrc->Size; Negative = pSrc->Negative; Num = new unsigned char[Size]; memcpy(Num,pSrc->Num,Size); }
//--------------------------------------------------------------------------- /* Конструктор копирования */ TMAN_HugeInt::TMAN_HugeInt(TMAN_HugeInt& pSrc) { Size = pSrc.Size; Negative = pSrc.Negative; Num = new unsigned char[Size]; memcpy(Num,pSrc.Num,Size); }
//--------------------------------------------------------------------------- /* Конструктор с параметром в виде целого */ TMAN_HugeInt::TMAN_HugeInt(int pNum) { Size = TMAN_HUGE_INT_SIZE; Num = new unsigned char[Size]; SetZero(); operator=(pNum); }
//--------------------------------------------------------------------------- /* Деструктор. Освобождает память */ TMAN_HugeInt::~TMAN_HugeInt() { delete Num; }
//--------------------------------------------------------------------------- /* Преобразование числа в двоичной форме в указанный буфер Размер буфера должен быть равен размеру числа * 8 + 2 (для знака и завершающего нуля) Можно воспользоваться методом GetBinStrSize для получения этого размера. Если буфер меньше - будет вылет */ char * TMAN_HugeInt::ToBinStr(char * pBuffer) { int i,j,BufPos = 0; bool FlagStart = true; unsigned char Current; setmem(pBuffer,GetBinStrSize(),0); if (Negative) pBuffer[BufPos++] = '-'; for (i=0;i<Size;i++) { Current = Num[i]; if (Current == 0) { // Если байт нулевой if (!FlagStart) { // байт нулевой, но он не самый старший // Добавляем к буферу 8 нулей for (j=0;j<8;j++) pBuffer[BufPos++] = '0'; } continue; } // байт ненулевой - побитовое сканирование for (j=0;j<8;j++) { if ((Current&128)==0) { if (!FlagStart) pBuffer[BufPos++] = '0'; } else { pBuffer[BufPos++] = '1'; FlagStart = false; } Current = Current << 1; } } // Если после выхода из цикла флаг остался установлен - значит // все байты нулевые, т.е. число 0 /* TODO : Сделать проверку на 0 в самом начале */ if (FlagStart) pBuffer[0] = '0'; return pBuffer; }
//--------------------------------------------------------------------------- /* Преобразование в компьютерную форму */ char* TMAN_HugeInt::ToITStr(char * pBuf) { TMAN_HugeInt Temp(this),Temp1,Temp2; char *Prist[]={ " б"," Кб"," Мб"," Гб"," Тб"," Пб"," Эб"," Зб"," Иб" }; int Index = -1; int i;
Temp2 = Temp; while (!Temp.IsZero()) { Temp1 = Temp2; Temp2 = (Temp*10)/1024; Temp/= 1024; Index++; if (Index == 7) break; } if (Index == -1) Index = 0;
Temp1.ToDecStr(pBuf); i = strlen(pBuf); if (i >1) { pBuf[i] = pBuf[i-1]; pBuf[i-1] = '.'; pBuf[i+1] = 0; } strcat(pBuf,Prist[Index]); return pBuf; }
//--------------------------------------------------------------------------- /* Преобразование в десятичную форму */ char* TMAN_HugeInt::ToDecStr(char * pBuf) { int Index = 0,i,j,t; TMAN_HugeInt Temp(this),Temp1; int Razryad; unsigned char Tmp; if (IsZero()) { pBuf[Index++] = '0'; goto ExitProc; }
while (!Temp.IsZero()) { Temp1 = Temp % 10; Razryad = Temp1.ToInt(); pBuf[Index++] = '0' + Razryad; Temp/=10; }
if (Negative) pBuf[Index++] = '-';
ExitProc: pBuf[Index] = 0; i = 0; j = Index - 1; while(i<j) { Tmp = pBuf[i]; pBuf[i++] = pBuf[j]; pBuf[j--] = Tmp; } return pBuf; }
//--------------------------------------------------------------------------- /* Возвращает остаток от деления */ TMAN_HugeInt TMAN_HugeInt::operator%(TMAN_HugeInt pNum) { TMAN_HugeInt Temp(this),Temp1,Temp2; Temp1 = operator/(pNum); Temp2 = operator-(Temp1 * pNum); return Temp2; }
//--------------------------------------------------------------------------- /* Присваивание целого числа */ TMAN_HugeInt TMAN_HugeInt::operator=(int pNum) { int j=Size-1; unsigned int i;
SetZero();
if (pNum == 0) return *this;
if (pNum < 0) { Negative = true; pNum *= (-1); }
for (i=0;i<sizeof(pNum);i++) { Num[j--] = pNum&255; pNum = pNum>>8; } return *this; }
//--------------------------------------------------------------------------- /* Присваивание огромного числа Если размера нехватает - исключение 1 */ TMAN_HugeInt TMAN_HugeInt::operator=(TMAN_HugeInt pNum) { if (pNum.Size > Size) throw EOverflow("Присваиваемое число большего размера"); SetZero(); Negative = pNum.Negative; memcpy(Num,pNum.Num,Size); return *this; }
//--------------------------------------------------------------------------- /* Оператор сдвига влево Не меняет текущий объект */ TMAN_HugeInt TMAN_HugeInt::operator<<(int pCount) { TMAN_HugeInt Tmp(this); Tmp.ShiftLeft(pCount); return Tmp; }
//--------------------------------------------------------------------------- /* Оператор сдвига влево Меняет текущий объект */ TMAN_HugeInt TMAN_HugeInt::operator<<=(int pCount) { ShiftLeft(pCount); return *this; }
//--------------------------------------------------------------------------- /* Оператор сдвига вправо Не меняет текущий объект */ TMAN_HugeInt TMAN_HugeInt::operator>>(int pCount) { TMAN_HugeInt Tmp(this); Tmp.ShiftRight(pCount); return Tmp; }
//--------------------------------------------------------------------------- /* Оператор сдвига вправо Меняет текущий объект */ TMAN_HugeInt TMAN_HugeInt::operator>>=(int pCount) { ShiftRight(pCount); return *this; }
//--------------------------------------------------------------------------- /* Функция сдвига влево текущего объекта */ void TMAN_HugeInt::ShiftLeft(int pCount) { int i; unsigned char Current; int Bit = 0; int TmpBit;
// Если сдвигаем больше чем вся длина - получаем 0 if (pCount > (Size * 8)) { SetZero(); return; }
if (pCount <=0) return;
while (pCount > 0) { // Бежим столько раз - сколько сдвиг i = Size-1; Bit = 0; while(i >= 0) { // Собственно сдвиг Current = Num[i]; TmpBit = ((Current&128)==0)?0:1; Num[i--] = (Current<<1)|Bit; Bit = TmpBit; } pCount--; } return; }
//--------------------------------------------------------------------------- /* Функция сдвига вправо текущего объекта */ void TMAN_HugeInt::ShiftRight(int pCount) { int i; unsigned char Current; int Bit = 0; int TmpBit;
// Если сдвигаем больше чем вся длина - получаем 0 if (pCount > (Size * 8)) { SetZero(); return; }
if (pCount <=0) return;
while (pCount > 0) { // Бежим столько раз - сколько сдвиг i = 0; Bit = 0; while(i < Size) { // Собственно сдвиг Current = Num[i]; TmpBit = ((Current&1)==0)?0:128; Num[i++] = (Current>>1)|Bit; Bit = TmpBit; } pCount--; } return; }
//--------------------------------------------------------------------------- /* Оператор сложения двух объектов Текущий объект остается без изменений Знаки объектов учитываются */ TMAN_HugeInt TMAN_HugeInt::operator+(TMAN_HugeInt pNum) { TMAN_HugeInt Tmp(this); // Если знаки чисел одинаковые - то вне зависимости от того какие они // числа нужно сложить if (Negative == pNum.Negative) Tmp.Add(pNum); else { // Знаки чисел разные. // Оставляем знак того числа, которое больше и из него же вычитаем // меньшее if (Tmp.Less(pNum)) { pNum.Sub(Tmp); Tmp = pNum; } else Tmp.Sub(pNum); } return Tmp; }
//--------------------------------------------------------------------------- /* Метод добавления к текущему объекту другого такого же Если размеры несовпадают - исключение EInvalidArgument При переполнении - Исключение EOverflow ДОБАВЛЯЕТСЯ ПО МОДУЛЮ */ void TMAN_HugeInt::Add(TMAN_HugeInt &pNum) { int Hvost,i; unsigned int Current,Target,Summa; if (pNum.Size != Size) throw EInvalidOp("При сложении не совпдает размер операндов");
Hvost = 0;
for (i=Size-1;i>=0;i--) { Current = Num[i]; Target = pNum.Num[i]; Summa = Current + Target + Hvost; Num[i] = (Summa&255); Hvost = Summa >> 8; } if (Hvost > 0) throw EOverflow("Переполнение огромного целого");; }
//--------------------------------------------------------------------------- /* Возвращает истину, если объект нулевой */ bool TMAN_HugeInt::IsZero(void) { bool Ret = true; int i; for(i=0;i<Size;i++) if (Num[i] != 0) { Ret = false; break; } return Ret; }
//--------------------------------------------------------------------------- /* Присваивает объекту значение 0 */ void TMAN_HugeInt::SetZero(void) { setmem(Num,Size,0); Negative = false; }
//--------------------------------------------------------------------------- /* Умножает текущий объект на указанный При переполнении - исключение 2 Знаки объекта не меняются - умножение идет по модулю */ void TMAN_HugeInt::Mul(TMAN_HugeInt pNum) { TMAN_HugeInt Result,Temp,Temp1; int i; int LastByte;
if (IsZero()||pNum.IsZero()) { SetZero(); return; }
Temp = *this; LastByte = pNum.Size - 1; for (i=0;i<pNum.Size*8;i++) { if ((pNum.Num[LastByte]&1) == 1) { // После сдвига текущий объект не может быть меньше исходного // Если это произошло - значит значимые цифры исчезли Temp1 = Temp<<i; if (Temp1.Less(Temp)) throw EOverflow("Переполнение при умножении"); Result = Result + Temp1; } pNum.ShiftRight(1); } operator=(Result); }
//--------------------------------------------------------------------------- /* Оператор умножения. Не трогает текущий объект Знаки объектов учитываются */ TMAN_HugeInt TMAN_HugeInt::operator*(TMAN_HugeInt pNum) { TMAN_HugeInt Tmp(this); Tmp.Mul(pNum); if ((Tmp.Negative)&&(pNum.Negative)) Tmp.Negative = false; else if((Tmp.Negative)||(pNum.Negative)) Tmp.Negative = true;
return Tmp; }
//--------------------------------------------------------------------------- /* Оператор деления. Не трогает текущий объект Знаки объектов учитываются */ TMAN_HugeInt TMAN_HugeInt::operator/(TMAN_HugeInt pNum) { TMAN_HugeInt Tmp(this); Tmp.Div(pNum); if ((Tmp.Negative)&&(pNum.Negative)) Tmp.Negative = false; else if((Tmp.Negative)||(pNum.Negative)) Tmp.Negative = true;
return Tmp; }
//--------------------------------------------------------------------------- /* Оператор деления. Трогает текущий объект Знаки объектов учитываются */ TMAN_HugeInt TMAN_HugeInt::operator/=(TMAN_HugeInt pNum) { operator=(operator/(pNum)); return *this; }
//--------------------------------------------------------------------------- /* Возвращает истину, если текущий объект меньше pNum по модулю */ bool TMAN_HugeInt::Less(TMAN_HugeInt pNum) { int i; bool Ret = false;
for (i=0;i<Size;i++) { if ((Num[i] == 0)&&(pNum.Num[i] == 0)) continue; if (Num[i] == pNum.Num[i]) continue; if (Num[i] < pNum.Num[i]) Ret = true; break; } return Ret; }
//--------------------------------------------------------------------------- /* Возвращает истину, если текущий объект больше pNum по модулю */ bool TMAN_HugeInt::Gross(TMAN_HugeInt pNum) { int i; bool Ret = false;
for (i=0;i<Size;i++) { if ((Num[i] == 0)&&(pNum.Num[i] == 0)) continue; if (Num[i] == pNum.Num[i]) continue; if (Num[i] > pNum.Num[i]) Ret = true; break; } return Ret; }
//--------------------------------------------------------------------------- /* Возвращает истину, если текущий объект равен pNum по модулю */ bool TMAN_HugeInt::Equ(TMAN_HugeInt pNum) { int i; bool Ret = true; for (i=0;i<Size;i++) { if (Num[i] != pNum.Num[i]) { Ret = false; break; } } return Ret; }
//--------------------------------------------------------------------------- /* Вычитает из текущего объекта указанный по модулю */ void TMAN_HugeInt::Sub(TMAN_HugeInt pNum) { int i,Hvost; unsigned char Part1,Part2; if (pNum.IsZero()) return; if (Equ(pNum)) { SetZero(); return; } Hvost = 0; for(i=Size-1;i>=0;i--) { Part1 = Num[i] - Hvost; Part2 = pNum.Num[i]; if (Part1 < Part2) Hvost = 1; else if (Num[i] != 0) Hvost = 0; Num[i] = Part1 - Part2; } }
//--------------------------------------------------------------------------- /* Оператор вычитания двух объектов Текущий объект остается без изменений Знаки объектов учитываются */ TMAN_HugeInt TMAN_HugeInt::operator-(TMAN_HugeInt pNum) { TMAN_HugeInt Tmp(this); if (Tmp.Negative!=pNum.Negative) { // Знаки объектов разные. Выполняем сложение и сохраняем знак исходного Tmp.Add(pNum); } else { // Знаки одинаковые // Выполняем вычитание из большего меньшего и меняем знак if (Tmp.Less(pNum)) { pNum.Sub(Tmp); Tmp = pNum; Tmp.Negative = !Tmp.Negative; } else Tmp.Sub(pNum); } return Tmp; }
//--------------------------------------------------------------------------- /* делит текущий объект на указанный. Делится по модулю, знаки не используются */ void TMAN_HugeInt::Div(TMAN_HugeInt pDiv) { int SourceDigit; int TargetDigit; int Shift; TMAN_HugeInt TempSource(this);
// Деление на 0 - исключение if (pDiv.IsZero()) throw EOverflow("Деление на 0"); // Деление нуля - выход if (IsZero()) return; if (Less(pDiv)) { // Делитель больше делимого - получится 0 SetZero(); return; }
// Длина текущего числа SourceDigit = LengthBin(); TargetDigit = pDiv.LengthBin();
SetZero();
Shift = SourceDigit - TargetDigit; pDiv.ShiftLeft(Shift);
while (Shift > 0) { if (!TempSource.Less(pDiv)) { Num[Size-1]|=1; TempSource.Sub(pDiv); } pDiv.ShiftRight(1); Shift--; ShiftLeft(1); }
if (!pDiv.Gross(TempSource)) Num[Size-1]|=1;
return; }
//--------------------------------------------------------------------------- /* Возвращает длину числа в разрядах. Для нулевого вернет 0 */ int TMAN_HugeInt::LengthBin(void) { int Ret = 0; int i,j; if (!IsZero()) { i = 0; while (Num[i] == 0) i++; // Нашли первый значимый байт Ret = (Size - i) * sizeof(unsigned char) * 8;
// Далее ищем первый значимый бит j = 128; while (j > 0) { if ((Num[i]&j) != 0) break; else { Ret--; j/=2; } } // while (j > 0) } // if (!IsZero())
return Ret; }
//--------------------------------------------------------------------------- /* Пытается преобразовать в целое число. При переполнении - вылетает с эксепшином EOverflow */ int TMAN_HugeInt::ToInt(void) { int Ret=0; int Mult = 1; unsigned int i,j;
if (Gross(MaxInt)) throw EOverflow("Число не помещается в int");
j = Size - 1;
for (i=0;i<sizeof(int);i++) { Ret += Num[j--] * Mult; Mult *= 256; }
if (Negative) Ret *= -1;
return Ret; }
//--------------------------------------------------------------------------- /* Оператор сравнения < */ bool operator<(TMAN_HugeInt pNum1,TMAN_HugeInt pNum2) { return pNum1.Less(pNum2); }
//--------------------------------------------------------------------------- /* Оператор сравнения > */ bool operator>(TMAN_HugeInt pNum1,TMAN_HugeInt pNum2) { return pNum1.Gross(pNum2); }
//--------------------------------------------------------------------------- /* Оператор сравнения == */ bool operator==(TMAN_HugeInt pNum1,TMAN_HugeInt pNum2) { return pNum1.Equ(pNum2); }
//--------------------------------------------------------------------------- /* Оператор сравнения != */ bool operator!=(TMAN_HugeInt pNum1,TMAN_HugeInt pNum2) { return !pNum1.Equ(pNum2); }
|
Сам код можно не критиковать - чисто экспериментальный класс делал когда-то для развлечения. Просто интересно: что ему надо? Метод, который он не может найти - объявлен и определен. (Это конструктор копирования)
|