Efficient Exponentiation For HUGE Numbers (I'm Talking Googols) - c++

I am in the midst of solving a simple combination problem whose solution is 2^(n-1).
The only problem is 1 <= n <= 2^31 -1 (max value for signed 32 bit integer)
I tried using Java's BigInteger class but It times out for numbers 2^31/10^4 and greater, so that clearly doesn't work out.
Furthermore, I am limited to using only built-in classes for Java or C++.
Knowing I require speed, I chose to build a class in C++ which does arithmetic on strings.
Now, when I do multiplication, my program multiplies similarly to how we multiply on paper for efficiency (as opposed to repeatedly adding the strings).
But even with that in place, I can't multiply 2 by itself 2^31 - 1 times, it is just not efficient enough.
So I started reading texts on the problem and I came to the solution of...
2^n = 2^(n/2) * 2^(n/2) * 2^(n%2) (where / denotes integer division and % denotes modulus)
This means I can solve exponentiation in a logarithmic number of multiplications. But to me, I can't get around how to apply this method to my code? How do I choose a lower bound and what is the most efficient way to keep track of the various numbers that I need for my final multiplication?
If anyone has any knowledge on how to solve this problem, please elaborate (example code is appreciated).
UPDATE
Thanks to everyone for all your help! Clearly this problem is meant to be solved in a realistic way, but I did manage to outperform java.math.BigInteger with a power function that only performs ceil(log2(n)) iterations.
If anyone is interested in the code I've produced, here it is...
using namespace std;
bool m_greater_or_equal (string & a, string & b){ //is a greater than or equal to b?
if (a.length()!=b.length()){
return a.length()>b.length();
}
for (int i = 0;i<a.length();i++){
if (a[i]!=b[i]){
return a[i]>b[i];
}
}
return true;
}
string add (string& a, string& b){
if (!m_greater_or_equal(a,b)) return add(b,a);
string x = string(a.rbegin(),a.rend());
string y = string(b.rbegin(),b.rend());
string result = "";
for (int i = 0;i<x.length()-y.length()+1;i++){
y.push_back('0');
}
int carry = 0;
for (int i =0;i<x.length();i++){
char c = x[i]+y[i]+carry-'0'-'0';
carry = c/10;
c%=10;
result.push_back(c+'0');
}
if (carry==1) result.push_back('1');
return string(result.rbegin(),result.rend());
}
string multiply (string&a, string&b){
string row = b, tmp;
string result = "0";
for (int i = a.length()-1;i>=0;i--){
for (int j= 0;j<(a[i]-'0');j++){
tmp = add(result,row);
result = tmp;
}
row.push_back('0');
}
return result;
}
int counter = 0;
string m_pow (string&a, int exp){
counter++;
if(exp==1){
return a;
}
if (exp==0){
return "1";
}
string p = m_pow(a,exp/2);
string res;
if (exp%2==0){
res = "1"; //a^exp%2 is a^0 = 1
} else {
res = a; //a^exp%2 is a^1 = a
}
string x = multiply(p,p);
return multiply(x,res);
//return multiply(multiply(p,p),res); Doesn't work because multiply(p,p) is not const
}
int main(){
string x ="2";
cout<<m_pow(x,5000)<<endl<<endl;
cout<<counter<<endl;
return 0;
}

As mentioned by #Oli's answer, this is not a question of computing 2^n as that's trivially just a 1 followed by 0s in binary.
But since you want to print them out in decimal, this becomes a question of how to convert from binary to decimal for very large numbers.
My answer to that is that it's not realistic. (I hope this question just stems from curiosity.)
You mention trying to compute 2^(2^31 - 1) and printing that out in decimal. That number is 646,456,993 digits long.
Java BigInteger can't do it. It's meant for small numbers and uses O(n^2) algorithms.
As mentioned in the comments, there are no built-in BigNum libraries in C++.
Even Mathematica can't handle it: General::ovfl : Overflow occurred in computation.
Your best bet is to use the GMP library.
If you're just interested in seeing part of the answer:
2^(2^31 - 1) = 2^2147483647 =
880806525841981676603746574895920 ... 7925005662562914027527972323328
(total: 646,456,993 digits)
This was done using a close-sourced library and took roughly 37 seconds and 3.2 GB of memory on a Core i7 2600K # 4.4 GHz including the time needed to write all 646 million digits to a massive text file.
(It took notepad longer to open the file than needed to compute it.)
Now to answer your question of how to actually compute such a power in the general case, #dasblinkenlight has the answer to that which is a variant of Exponentiation by Squaring.
Converting from binary to decimal for large numbers is a much harder task. The standard algorithm here is Divide-and-Conquer conversion.
I do not recommend you try to implement the latter - as it's far beyond the scope of starting programmers. (and is also somewhat math-intensive)

You don't need to do any multiplication at all. 2^(n-1) is just 1 << (n-1), i.e. 1 followed by (n-1) zeros (in binary).

The easiest way to apply this method in your code is to apply it the most direct way - recursively. It works for any number a, not only for 2, so I wrote code that takes a as a parameter to make it more interesting:
MyBigInt pow(MyBigInt a, int p) {
if (!p) return MyBigInt.One;
MyBigInt halfPower = pow(a, p/2);
MyBigInt res = (p%2 == 0) ? MyBigInt.One : a;
return res * halfPower * halfPower;
}

Related

Recursion for evaluating log(1+x) using taylor series of the same

#include<iostream>
using namespace std;
double log(double x,int n)
{
static double p = x ;
double s;
if(n==1)
return x;
else
{
s=log(x,n-1);
p*=x;
if(n%2==0)
return s - (p/n);
else
return s + (p/n);
}
}
int main()
{
double r = log(1,15);
cout << r;
return 0;
}
I tried writing the above function for evaluating the log(1+x) function using its taylor series with recursion. But it didn't gave the result as I expected.
Eg :
ln(2) = 0.693 whereas my code gave 0.725. In the above code, n represents the number of terms.
Also I am new to this platform, so can I say that the above question is complete or does it need some additional information for further explanation?
There is nothing wrong with that piece of code: this has obviously got to do with the rate of convergence of the Taylor series.
If you take n = 200 instead of n = 15 in your code, the approximation error will be low enough that the first two decimals of the exact solution ln(2) = 0.693147... will be the correct ones.
The more you increase the n parameter, the better approximation you will get of ln(2).
Your program does converge to the right number, just very slowly...
log(1,15) returns 0.725, as you noticed, log(1,50) is 0.683, log(1,100) is 0.688, and log(1,200) is 0.691. That's getting close to the number you expected, but still a long way to go...
So there is no C++ or recursion bug in your code - you just need to find a better Taylor series to calculate log(X). Don't look for a Taylor series for log(1+x) - these will typically assume x is small, and converge quickly for small x, not for x=1.

pigeon hole / multiple numbers

input : integer ( i'll call it N ) and (1 <= N <= 5,000,000 )
output : integer, multiple of N and only contains 0,7
Ex.
Q1 input : 1 -> output : 7 ( 7 mod 1 == 0 )
Q2 input : 2 -> output : 70 ( 70 mod 2 == 0 )
#include <string>
#include <iostream>
using namespace std;
typedef long long ll;
int remaind(string num, ll m)
{
ll mod = 0;
for (int i = 0; i < num.size(); i++) {
int digit = num[i] - '0';
mod = mod * 10 + digit;
mod = mod % m;
}
return mod;
}
int main()
{
int n;
string ans;
cin >> n;
ans.append(n, '7');
for (int i = ans.length() - 1; i >= 0; i--)
{
if (remaind(ans, n) == 0)
{
cout << ans;
return 0;
}
ans.at(i) = '0';
}
return 0;
}
is there a way to lessen the time complexity?
i just tried very hard and it takes little bit more time to run while n is more than 1000000
ps. changed code
ps2. changed code again because of wrong code
ps3. optimize code again
ps4. rewrite post
Your approach is wrong, let's say you divide "70" by 5. Then you result will be 2 which is not right (just analyze your code to see why that happens).
You can really base your search upon numbers like 77777770000000, but think more about that - which numbers you need to add zeros and which numbers you do not.
Next, do not use strings! Think of reminder for a * b if you know reminder of a and reminder of b. When you program it, be careful with integer size, use 64 bit integers.
Now, what about a + b?
Finally, find reminders for numbers 10, 100, 1000, 10000, etc (once again, do not use strings and still try to find reminder for any power of 10).
Well, if you do all that, you'll be able to easily solve the whole problem.
May I recommend any of the boost::bignum integer classes?
I suspect uint1024_t (or whatever... they also have 128, 256, and 512, bit ints already typedefed, and you can declare your own easily enough) will meet your needs, allowing you to perform a single %, rather than one per iteration. This may outweigh the performance lost when using bignum vs c++'s built-in ints.
2^1024 ~= 1.8e+308. Enough to represent any 308 digit number. That's probably excessive.
2^512 ~= 1.34e+154. Good for any 154 digit number.
etc.
I suspect you should first write a loop that went through n = 4e+6 -> 5e+6 and wrote out which string got the longest, then size your uint*_t appropriately. If that longest string length is more than 308 characters, you could just whip up your own:
typedef number<cpp_int_backend<LENGTH, LENGTH, unsigned_magnitude, unchecked, void> > myReallyUnsignedBigInt;
The modulo operator is probably the most expensive operation in that inner loop. Performing once per iteration on the outer loop rather than at the inner loop (O(n) vs O(n^2)) should save you quite a bit of time.
Will that plus the whole "not going to and from strings" thing pay for bignum's overhead? You'll have to try it and see.

Exponentiation for huge numbers by huge numbers

I've two huge natural numbers saved as strings: a and b. Each of the numbers can have up to 150 characters. I need to get result of ab in a reasonable time.
I searched for optimal solution, but always a is a big string and b - int.
I tried simply solution:
string power(string n1, string n2) {
string result = n1;
if(n2 == "0")
return "1";
do {
result = multiply(result, n1);
n2 = decrement(n2);
}
while(n2 != "1");
return result;
}
How can I get result in less time?
You need to calculate much less when you reuse results.
For Example:
5^8 = 5^4*5^4 = 5^2*5^2*5^2*5^2 = 5*5*5*5*5*5*5*5
You don't need to do all 7 multiplications, only 5*5, 5^2*5^2, 5^4*5^4 (3 multiplications)
The following code is Python code (because i wanted to easily test it), but I hope you see the point.
def powBase10(a,n):
if(n==0):
return 1
x=powBase10(a, int(n/10))
if(n%10==0):
return (x*x*x*x*x*x*x*x*x*x)
if(n%10==1):
return (a*x*x*x*x*x*x*x*x*x*x)
if(n%10==2):
return (a*a*x*x*x*x*x*x*x*x*x*x)
if(n%10==3):
return (a*a*a*x*x*x*x*x*x*x*x*x*x)
if(n%10==4):
return (a*a*a*a*x*x*x*x*x*x*x*x*x*x)
if(n%10==5):
return (a*a*a*a*a*x*x*x*x*x*x*x*x*x*x)
if(n%10==6):
return (a*a*a*a*a*a*x*x*x*x*x*x*x*x*x*x)
if(n%10==7):
return (a*a*a*a*a*a*a*x*x*x*x*x*x*x*x*x*x)
if(n%10==8):
return (a*a*a*a*a*a*a*a*x*x*x*x*x*x*x*x*x*x)
if(n%10==9):
return (a*a*a*a*a*a*a*a*a*x*x*x*x*x*x*x*x*x*x)
def powBase2(a,n):
if(n==0):
return 1
x=powBase2(a, int(n/2))
if(n%2==0):
return (x*x)
if(n%2==1):
return (a*x*x)
The code should be faster when you use base 2 instead of base 10.
The reason why should adjust the algorithm to your base is, that the division by the base can be done by deleting the last digit, so there is no real calculation needed for division.
The number of multiplications you need should be logarithmic with this approach instead of linear so it should be no problem with a few hundred digits.
You could optimize the base-10 code again with the same approach
for example instead of:
x*x*x*x*x*x
use:
y=x*x
y=y*y*y
But this will only result in a constant speedup.

Find the length of an integer in C++ [duplicate]

This question already has answers here:
C++ - how to find the length of an integer
(17 answers)
Closed 7 years ago.
In Java, I use
int length = String.valueOf(input).length();
to find the length of an integer.
My question is: Are there any similar ways to do so in C++?
I have already tried the for loops and while loops such as:
while (input > 0){
input/=10;
count++;
So, apart from the loops are there anything else available in C++. Thank you for your answer.
If you want an exact counterpart of what you have written in Java, you can use:
int length = to_string(input).length();
Note that to_string is a C++11 feature. Also, be careful with negative numbers.
The number of digits can be calculated without converting to a string first by using the number's logarithm:
std::size_t intlen(int i) {
if (i == 0) return 1;
else if (i < 0) return 2 + static_cast<std::size_t>(std::log10(-i));
else if (i > 0) return 1 + static_cast<std::size_t>(std::log10(i));
}
The logartihm is only defined for positive numbers, so negatives and zero have to be handled separately, counting the - sign as an additional character. Replace log10 by log2 to obtain the number of binary digits (this is possible for any base).
Note however that converting to strings first (e.g. by using std::to_string) is a locale-dependent operation and can thus yield different results for different language settings - some locales insert a thousands separator (e.g. 100,000) which will not show up using the above formula.
unsigned int number_of_digits = 0;
do {
++number_of_digits;
n /= base; } while (n);
// n is your base number.
Talking about pre-C++11, you can use the same approach, but with sprintf.
Convert integer to a char array, and then get its length:
char buffer[30];
int length = sprintf(buffer, "%d", input);
Here is the working IDEOne example.
Apart from the loops there is recursion. For example, for positive integers you can do:
unsigned int len(unsigned int n)
{
return n ? len(n/10)+1 : 0;
}

first and last k digits of number n^n

i have written a c++ code for generating first and last k digits of a number as large as 10^9. (k<=9).
cin>>n>>k;
cout << (unsigned long)floor(pow(10.0, modf(n*log10((double)n), &dummy) + k - 1)) << " "; // code that prints the first k digits
long long int ans = foo(n,k); // function that prints the last k digits
if(ans==0)
{
for(int i=0;i<k;i++) cout << "0";
}
else{
stringstream ss;
string s;
ss<<ans;
ss>>s;
if(s.size()!=k)
{
for(int i=0;i<(k-s.size());i++)
s="0"+s;
}
cout<<s;
}
where function foo() is:
long long int foo(int n, int k) // code of the function
{
long long int m=1;
for(; k > 0; k--) m*=10;
long long int r=1, t=n % m;
while(n)
{
if (n % 2)
r = r * t % m;
t = t * t % m;
n >>= 1;
}
return r;
}
this gives me output as:
if given 9 and 3 as inputs, it gives first and last 3 digits of 9 to the power 9 (9^9) i.e. 387 and 489. But I m still missing out some test cases.
Can anyone please help me finding out the test case for which my code wouldn't work ?
1 ≤ n ≤ 109, 1 ≤ k ≤ 9
the problem statement: http://www.codechef.com/problems/MARCHA4/
If n^n <= 10^9, in which case your code seems to work fine. However, if you allow bigger n, say 11^11, and ask for the last 4 digits of that, which are 0611, your code will only print 611. Basically, it doesn't print any leading zeroes when it should.
This doesn't really answer the question, and its almost trivially easy, but I figure it might be worth sharing. If there were a "long comment" capability I'd be using it.
EDIT: just noticed using str instead of repr will eliminate the L on its own
def firstAndLastDig(k, num):
s = str(num)
return (s[:k], s[-k:])
def firstAndLastDigSelfExp(k,n):
return firstAndLastDig(k,n**n)
Overflow is not an issue (the only thing is dealing with the L if you use repr instead of str),
firstAndLastDigSelfExp(6,12)
('891610', '448256')
firstAndLastDigSelfExp(42,491)
('209417336844579728122309696211520194012462', '160453713040914743773217804810667483135091')
And neither are leading zeroes
>>> firstAndLastDigSelfExp(4,9)
('3874', '0489')
This isn't do say the modular logs and stuff aren't cool - on the contrary I really liked reading about how you did this without generating the entire number. I didn't know about modf at all until reading OP's question and the body of foo is very interesting.
I think the problem is using floating point. Finding the first digit of a number actually requires perfect precision.
Unfortunately, the contest judge evidently doesn't understand that "number of significant digits" != "number of correct digits".
Perhaps there is some clever way to exactly compute (n*n, n = 10*9) without exhausting memory, but finding the first digits of a very good estimate is simply not the same as finding the first digits of the answer.
Assume that k = 9. Now, m = 1e9, and t <= 1e9 - 1.
t * t then may be as high as 1e18 - 2e9 + 1, which needs ... 59.8 bits.
Ok, not a problem with a 64-bit long long int, which has 63 bits of magnitude (and 1 of sign), but I'll leave this here so others don't repeat the same analysis.
Are you told that n is a positive integer? For example, (-8)^(-8) is perfectly well expressible in decimal but your program can't handle it.