Reputation: 1010
I wrote a C++ class for big unsigned integer containing up to 10^5
decimal digits, it has got a BASE = 10^9
and std::vector<long long>
inside to store actual number -
for example 754564575693573452
is stored as
std::vector<long long> number = {693573452, 754564575}
In the constructor I resize this vector to always contain some fixed number of long long
digits, lets say its 10^5, therefore a single addition of two big uints can have up to a 10^6 digits (which is 9 * 10^6
digits in BASE = 10^1
numeral system), and similarly for multiplication...
So there's a 9 times speed up for all arithmetic operations but this is noticed only for a few calculations on big numbers, for a cases with a lot of computations the performance slows down, and this is because of the class design, my constructor and default constructor always call resize function as I said before, which is linear time routine.
void Big_uint::read_num_str(const std::string& num_str)
{
// reading from num_str to number
}
Big_uint::Big_uint(const std::string& num_str = "0")
{
number.resize( 1000000 );
read_num_str(num_str);
}
Big_uint::Big_uint(const long long& num)
{
number.resize( 1000000 );
char buff[ 20 ];
_itoa_s(static_cast<int>(num), buff, 10);
std::string s = buff;
read_num_str(s);
}
and all the arithmetic operations are implemented in this way
Big_uint operator + (const Big_uint& left, const Big_uint& right)
{
Big_uint res; // resize() called here to initialize a vector
// add algorithm
return res;
}
Big_uint operator * (const Big_uint& left, const Big_uint& right)
{
Big_uint res; // resize() called here to initialize a vector
// some multiplication algorithm here (currently only naive O(n^2) implemented)
return res;
}
Thus, they become inefficient.
How can I have the vector be already initialized depending on the input in operator overloads ?
I dont wan't to change operator overloads to a member functions like add, mul, div
and pass them 3 parameters, where 3rd one would be a res
- a preallocated zero initialized Big_uint
to store the result of binary operation.
Upvotes: 1
Views: 293
Reputation: 29970
You shouldn't preallocate storage this way. Don't preallocate at all. At every operation, you know (approximately) the size of the result. For add, it is the maximum of the inputs' size plus one. For mul, it is the sum of the inputs' size. Always try to allocate only the necessary space to hold the number.
So, the default constructor shouldn't allocate at all. Every other constructor should check the size of the input, and allocate the necessary space. Operators should (conservatively) approximate the necessary space, and allocate accordingly.
A side note: you should use base 2^32 instead of 10^9 (or 2^64 on a 64-bit machine): it has slightly less memory consumption, and performance will be much better.
Side note 2: sizeof(long long) is usually 8, so you waste memory if you only store numbers less than 10^9 in it.
Upvotes: 3