Integer Class
Post date: Nov 27, 2013 3:17:47 AM
سلام
مدتی بود میخواستم کلاسی برای اعداد صحیح برزگ بنویسم. فرصت شد نوشتم. در نوشتن به این فکر میکردم که اصول اولیه اعداد صیحیح را میشود با برنامه نویسی خیلی بهتر گفت تا اصول پئانو در ریاضیات. البته در ریاضیات اعداد حقیقی هم هستند که بدون شک به شکل مشابه نمیشود آنها را بازسازی کرد. فقط یک زیر مجموعه شمارش پذیر از اونها را میشود شبیه سازی کرد.
کلاس زیر را میشود اصلاح کرد و بهترش کرد. این کلاس با رشتهها نوشته شده است. این طور بهتر است چون با رشتهها راحت تر میشود کار کرد تا بیتها. ولی مشکل این جاست که حجم ذخیره سازی عدد بالاتر است که در کامپوترهای امروزی یک مشکل به حساب نمیآید. البته قبل از نوشتن ایدۀ من این بود که از کنار هم گذاشتن متغیرهای معمولی استفاده کنیم. ولی نوشتن برنامه با رشته، طبیعی تر به نظر میرسد. من برای ضرب و تقسیم همان روشی را به کار بردهام که در دورۀ ابتدایی گفته میشود. مبنا 10 است ولی میشود به راحتی مبنا را عوض کرد.
#include
<string>
#include
<vector>
#include
<map>
#include
<iostream>
using
namespace
std;
inline
void
print_error(string
error)
{
cout<<
error;
}
class
Unsigned
{
public:
string
number;
private:
void
AddZeros(unsigned
n)
{
if(n
==
0)
return;
if(n
>
5000)
//
protecting
code
print_error("AddZero");
char*
c
=
new
char
[n
+
1];
for(unsigned
i
=
0;
i
<
n;
i++)
c[i]
=
'0';
c[n]
=
0;
number
=
string(c)
+
number;
delete
[]
c;
}
void
RemoveZeros()
{
unsigned
len
=
number.size();
if(len
==
0)
//
protecting
code
print_error("RemoveZeros");
const
char*
c
=
number.c_str();
unsigned
s
=
0;
while(c[s]
==
'0')
{
s++;
if(s
>=
len
-
1)
//
needed
if
number
==
"000"
break;
}
number
=
string(c
+
s);
}
unsigned
DigNum()
const
{
return
number.size();
}
void
SetDigNum(unsigned
len)
{
RemoveZeros();
if(DigNum()
<
len)
AddZeros(len
-
DigNum());
}
unsigned
Dig(unsigned
n)
const
{
unsigned
dignum
=
DigNum();
if(n
<
dignum)
return
number[dignum
-
n
-
1]
-
'0';
else
return
0;
}
void
SetDig(unsigned
dig,
unsigned
value)
{
unsigned
i
=
0;
while(true)
{
unsigned
dignum
=
DigNum();
unsigned
n
=
dig
+
i
+
1;
if(dignum
<
n)
{
SetDigNum(n);
dignum
=
DigNum();
}
number[dignum
-
n]
=
value
%
10
+
'0';
if(value
<
10)
break;
value
/=
10;
i++;
if(i
>
50)
//
protecting
code
break;
}
}
void
AddDig(unsigned
dig,
unsigned
value)
{
unsigned
dignum
=
DigNum();
unsigned
n
=
dig
+
1;
if(dignum
<
n)
{
SetDigNum(n);
dignum
=
DigNum();
}
number[dignum
-
n]
+=
value
%
10;
if(number[dignum
-
n]
>=
10
+
'0')
{
number[dignum
-
n]
-=
10;
AddDig(dig
+
1,1);
}
if(value
>=
10)
AddDig(dig
+
1,value
/
10);
}
void
SubDig(unsigned
dig,
unsigned
value)//
SubtractDig
{
unsigned
dignum
=
DigNum();
if(Dig(dig)
>=
value)
SetDig(dig,Dig(dig)
-
value);
else
{
if(dig
+
1
>=
dignum)
print_error("SubDig");
else
{
SubDig(dig
+
1,1);
SetDig(dig,10
+
Dig(dig)
-
value);
}
}
}
void
DivideBy(const
Unsigned&
U2,string&
ret_number,unsigned
min_sep)
const
{
const
Unsigned&
U1
=
*this;
if(U1
<
U2)
{
ret_number
+=
"0";
return;
}
unsigned
sep
=
1
+
min_sep;
string
str
=
U1.number;
char*
cstr
=
(char*)
str.c_str();
char
reserved_ch
=
cstr[sep];
cstr[sep]
=
0;
Unsigned
paraU1
=
string(cstr);
while(paraU1
<
U2)
{
if(ret_number
!=
"")
ret_number
+=
"0";
cstr[sep]
=
reserved_ch;
sep++;
reserved_ch
=
cstr[sep];
cstr[sep]
=
0;
paraU1
=
string(cstr);
}
//so
now
U2
<=
paraU1
string
para_number;
for(unsigned
i
=
1;;
i++)
{
Unsigned
I(i);
if(paraU1
<
I*U2)
{
para_number
=
(Unsigned(i
-
1)).number;
break;
}
if(i
>=
11)
{
print_error("division
by
zero");
return;
}
}
ret_number
+=
para_number;
Unsigned
paraQ
=
para_number;
if(reserved_ch
!=
0)
{
const
char*
c
=
U1.number.c_str();
Unsigned
paraRemainder
=
paraU1
-
paraQ*U2;
if(paraRemainder
==
Unsigned("0"))
{
Unsigned
newU1
=
string(c
+
sep);
newU1.DivideBy(U2,ret_number,0);
}
else
{
Unsigned
newU1
=
paraRemainder.number
+
string(c
+
sep);
newU1.DivideBy(U2,ret_number,paraRemainder.DigNum());
}
}
}
public:
string
GetStr()
{
return
number;
}
//-----------------------------------
void
operator
+=(const
unsigned&
value)
{
AddDig(0,value);
}
Unsigned
operator
+(const
Unsigned&
U)
const
{
Unsigned
ret
=
*this;
unsigned
U_dignum
=
U.DigNum();
for(unsigned
i
=
0;
i
<
U_dignum;
i++)
ret.AddDig(i,U.Dig(i));
ret.RemoveZeros();
return
ret;
}
void
operator
+=
(const
Unsigned&
U)
{
*this
=
*this
+
U;
}
Unsigned
operator
++()
{
*this
+=
Unsigned("1");
return
*this;
}
void
operator
-=
(const
Unsigned&
U)
{
*this
=
*this
-
U;
}
Unsigned
operator
--()
{
*this
-=
Unsigned("1");
return
*this;
}
Unsigned
operator
*(const
Unsigned&
u2)
const
{
const
Unsigned&
u1
=
*this;
Unsigned
ret;
unsigned
dignum1
=
u1.DigNum();
unsigned
dignum2
=
u2.DigNum();
for(unsigned
i
=
0;
i
<
dignum1;
i++)
for(unsigned
j
=
0;
j
<
dignum2;
j++)
ret.AddDig(
i
+
j
,
u1.Dig(i)*u2.Dig(j)
);
return
ret;
}
bool
operator
<
(const
Unsigned&
u2)
const
{
const
Unsigned&
u1
=
*this;
unsigned
dignum1
=
u1.DigNum();
unsigned
dignum2
=
u2.DigNum();
unsigned
max
=
dignum1
<=
dignum2
?
dignum2
:
dignum1;
for(unsigned
i
=
1
;
i
<=
max;
i++)
{
unsigned
dig1
=
u1.Dig(max
-
i);
//
delete
unsigned
dig2
=
u2.Dig(max
-
i);
//
delete
if(dig1
<
dig2)
return
true;
else
if(dig2
<
dig1)
return
false;
}
return
false;
}
bool
operator
>
(const
Unsigned&
u2)
const
{
const
Unsigned&
u1
=
*this;
return
u2
<
u1;
}
bool
operator
==
(Unsigned
u2)
const
{
Unsigned
u1
=
*this;
u1.RemoveZeros();
u2.RemoveZeros();
return
u1.number
==
u2.number;
}
bool
operator
<=
(const
Unsigned&
u2)
const
{
const
Unsigned&
u1
=
*this;
if(u1
<
u2)
return
true;
if(u1
==
u2)
return
true;
return
false;
}
bool
operator
>=
(const
Unsigned&
u2)
const
{
const
Unsigned&
u1
=
*this;
return
u2
<=
u1;
}
Unsigned
operator
-
(const
Unsigned&
u2)
const
{
const
Unsigned&
u1
=
*this;
if(u1
<=
u2)
return
Unsigned("0");
//
return
zero
Unsigned
ret
=
u1;
unsigned
dignum2
=
u2.DigNum();
for(unsigned
i
=
0;
i
<
dignum2;
i++)
ret.SubDig(i,u2.Dig(i));
ret.RemoveZeros();
return
ret;
}
Unsigned
operator
/
(const
Unsigned&
U2)
const
{
string
ret_number;
DivideBy(U2,ret_number,U2.DigNum()
-
1);
return
Unsigned(ret_number);
}
//-----------------------------------
Unsigned&
operator
=
(const
Unsigned&
U)
{
number
=
U.number;
return
*this;
}
Unsigned()
:
number("0")
{
}
Unsigned(string
_number)
:
number(_number)
{
}
Unsigned(unsigned
n)
:
number("0")
{
SetDig(0,n);
}
Unsigned(const
Unsigned&
U)
:
number(U.number)
{
}
};
class
Integer
{
public:
bool
negative;
Unsigned
abs;
void
Negate()
{
if(abs
==
Unsigned("0"))
negative
=
false;
else
{
if(negative
==
true)
negative
=
false;
else
negative
=
true;
}
}
string
GetStr()
{
string
ret;
if(negative)
ret
+=
"-";
ret
+=
abs.GetStr();
return
ret;
}
//-----------------------------------
Integer
operator
+(const
Integer&
I2)
const
{
const
Integer&
I1
=
*this;
Integer
ret;
if(I1.negative)
{
if(I2.negative)
{
ret.abs
=
I1.abs
+
I2.abs;
ret.Negate();
}
else
{
if(I1.abs
<
I2.abs)
ret.abs
=
I2.abs
-
I1.abs;
else
//
if
I2.abs
<=
I1.abs
{
ret.abs
=
I1.abs
-
I2.abs;
ret.Negate();
}
}
}
else
if(I2.negative)
ret
=
I2
+
I1;
else
ret.abs
=
I1.abs
+
I2.abs;
return
ret;
}
void
operator
+=
(const
Integer&
I)
{
*this
=
*this
+
I;
}
Integer
operator
++()
{
*this
+=
Integer("1");
return
*this;
}
void
operator
-=
(const
Integer&
I)
{
*this
=
*this
-
I;
}
Integer
operator
--()
{
*this
-=
Integer("1");
return
*this;
}
Integer
operator
*(const
Integer&
I2)
const
{
const
Integer&
I1
=
*this;
Integer
ret;
ret.abs
=
I1.abs
*
I2.abs;
if(
(!I1.negative
&&
I2.negative)
||
(I1.negative
&&
!I2.negative)
)
ret.Negate();
return
ret;
}
bool
operator
<
(const
Integer&
I2)
const
{
const
Integer&
I1
=
*this;
if(!I1.negative
&&
I2.negative)
return
false;
if(I1.negative
&&
!I2.negative)
return
true;
if(I1.negative
&&
I2.negative)
return
(I2.abs
<
I1.abs);
return
I1.abs
<
I2.abs;
}
bool
operator
>
(const
Integer&
I2)
const
{
const
Integer&
I1
=
*this;
return
I2
<
I1;
}
bool
operator
==
(const
Integer&
I2)
const
{
const
Integer&
I1
=
*this;
if(I1.abs
==
I2.abs
&&
I1.negative
==
I2.negative)
return
true;
return
false;
}
bool
operator
<=
(const
Integer&
I2)
const
{
const
Integer&
I1
=
*this;
if(I1
<
I2)
return
true;
if(I1
==
I2)
return
true;
return
false;
}
bool
operator
>=
(const
Integer&
I2)
const
{
const
Integer&
I1
=
*this;
return
I2
<=
I1;
}
Integer
operator
-
(Integer
I2)
const
{
const
Integer&
I1
=
*this;
I2.Negate();
return
I1
+
I2;
}
Integer
operator
/
(const
Integer&
I2)
const
{
const
Integer&
I1
=
*this;
Integer
ret;
ret.abs
=
I1.abs
/
I2.abs;
if(
(!I1.negative
&&
I2.negative)
||
(I1.negative
&&
!I2.negative)
)
ret.Negate();
return
ret;
}
//-----------------------------------
Integer()
:
abs(),
negative(false)
{
}
Integer(string
number)
:
abs(),
negative(false)
{
if(number[0]
==
'-')
{
negative
=
true;
const
char*
c
=
number.c_str();
abs
=
Unsigned(string(c
+
1));
}
else
abs
=
Unsigned(number);
if(abs
==
Unsigned(0))
negative
=
false;
}
Integer(int
n):
abs(),
negative(false)
{
if(0
<=
n)
abs
=
Unsigned(unsigned(n));
else
{
negative
=
true;
abs
=
Unsigned(unsigned(-n));
}
if(n
==
0)
negative
=
false;
}
Integer(const
Integer&
I):
abs(I.abs),
negative(I.negative)
{
}
};
inline
ostream&
operator
<<
(ostream&,Integer
I)
{
cout<<
I.GetStr();
return
cout;
}
int
main()
{
Integer
a("100");
Integer
b("-110");
cout<<
a
-
b;
cin.get();
}
Output:
210