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.
Related
Basically, how it works is it converts a number into a string, and if it finds any even in the string then it gives foundEven variable a positive value. The same goes for odd numbers.
(One thing I don't get is why if I switch the '>' sign with an '<' in if (FoundEvenSignedInt < FoundOddSignedInt) it gives you the correct result of an odd number.)
Are there any ways I could improve the code? Are there any bugs in it? I'm fairly new at C++ programing.
#include <string>
#include <cstddef>
int IsPrime(long double a)
{
int var;
long double AVar = a;
signed int FoundEvenSignedInt, FoundOddSignedInt;
std::string str = std::to_string(a);
std::size_t foundEven = str.find_last_of("2468");
std::size_t foundOdd = str.find_last_of("3579");
FoundEvenSignedInt = foundEven;
FoundOddSignedInt = foundOdd;
if (FoundEvenSignedInt < FoundOddSignedInt)
{
var = 1;
goto EndOfIsPrimeFunction;
}
if (FoundEvenSignedInt > FoundOddSignedInt)
{
var = 2;
goto EndOfIsPrimeFunction;
}
// This if statement kept giving me this weird warning so I made it like this
if (FoundEvenSignedInt == -1)
{
if (FoundOddSignedInt == -1)
{
if (AVar == 10 || 100 || 1000 || 10000 || 100000 || 1000000)
{
var = 2;
goto EndOfIsPrimeFunction;
}
}
}
EndOfIsPrimeFunction:
return var;
}
Here are some ways to improve the code.
The Collatz conjecture is about integers. long double is a data type of floating point numbers. It is unsuitable for checking the conjecture. You need to work with an integral data type such as unsigned long long. If this doesn't have enough range for you, you need to work with some kind of Bignum dat atype. There isn't any in the standard C library, you need to find a third party one.
The Collatz conjecture has nothing to do with being prime. It is about even and odd integers. It is true that all prime numbers except 2 are odd, but this fact doesn't help you.
The data type to answer yes/no questions in C++ is bool. By convention. for any other numeric data type zero means "no" and all other values mean "yes" (technically, when converted to bool, zero is converted to false and other values to true, so you can do things like if (a % 2). A function that returns 1 and 2 for yes and no is highly unconventional.
A natural method of checking whether a number is odd is this:
bool isOdd (unsigned long long a)
{
return a % 2;
}
It is somewhat faster than your code (by a factor of about 400 on my computer), gives correct results every time, is readable, and has zero goto statements.
Instead of the if(AVar == 10 || 100 || ..., you can say if(!(AVar % 10)).
I am fairly new to C++. I am trying to write a recursive binary function. The binary output needs to be 4 bits, hence the logic around 15 and the binary string length. It converts to binary correctly, the problem I am having is ending the recursive call and returning the binary string to the main function. It seems to just backwards through the call stack? Can someone help me understand what is going on?
Assuming using namespace std. I know this is not good practice, however it is required for my course.
string binary(int number, string b){
if (number > 0 && number < 15){
int temp;
temp = number % 2;
b = to_string(temp) + b;
number = number / 2;
binary(number, b);
}
else if (number > 15){
b = "1111";
number = number - 15;
binary(number, b);
}
else if (number == 15){
b = "11110000";
return b;
}
//should be if number < 1
else{
int s = b.size();
//check to make sure the binary string is 4 bits or more
if (s >= 4){
return b;
}
else{
for (int i = s; i < 4; i++){
b = '0' + b;
}
return b;
}
}
}
You have your function returning a string, but then you require the user to supply an initialized string for you, and you throw away the return value except for the base cases of 15 and 0. The rest of the time, your actual communication is using the parameter b. This multiple communication will cause some headaches.
I also note that you return a properly padded 4-bit number in normal cases; however, you force a return an 8-bit 15 for the exact value 15. Is this part of the assignment specification?
The logic for larger numbers is weird: if the amount is more than 15, you return "1111" appended to the representation for the remainder. For instance, 20 would return as binary(5) followed by "1111", or "1011111", which is decidedly wrong. Even stranger, it appears that any multiple of 15 will return "11110000", since that clause (== 15) overwrites any prior value of b.
I suggest that you analyze and simplify the logic. There should be two cases:
(BASE) If number == 0, return '0'
(RECUR) return ['1' (for odd) else '0'] + binary(number / 2)
You also need a top-level wrapper that checks the string length, padding out to 4 digits if needed. If the "wrapper" logic doesn't fit your design ideas, then drop it, and work only with the b parameter ... but then quit returning values in your other branches, since you don't use them.
Does this get you moving?
In generating the 'check digit' in Luhn's algorithm
The check digit (x) is obtained by computing the sum of digits then computing 9 times that value modulo 10 (in equation form, (67 * 9
mod 10)). In algorithm form: Compute the sum of the digits (67).
Multiply by 9 (603). The last digit, 3, is the check digit.
Natural instincts point towards taking an id as a string to make individual digit operation easier. But there seems to be no way to extract a digit at a time through stringstream since there's no delimiter(as far as I can tell). So the process turns into a cumbersome conversion of individual characters to ints...
There's modulus for each digit approach as well, which also takes a bit of work.
I guess what I'm getting at is that I feel maybe I'm overlooking a more elegant way taking an input and operating on the input as if they were single digit inputs.
Use modular arithmetic to simply the equation like following :-
checkdigit = (sum_digits*9)%10
= ((sum_digits)%10*9)%10
Now sum_digits%10 is very simple to evaluate using strings.
C++ implementation :-
#include<iostream>
using namespace std;
int main() {
char* str = new char[100];
cout<<"Enter the String: ";
cin>>str;
int val = 0;
for(int i=0;str[i]!=0;i++) {
val = (val+str[i]-'0')%10;
}
val = (val*9)%10;
cout<<"Checkdigit("<<str<<") = "<<val;
return 0;
}
Stringstream has to calculate all digits and then convert each digit to a char by adding '0'. You'd have to subtract '0' again to get the digit values back. You'd be better off using the modulo approach directly.
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;
}
Suppose input no is f(354683257) returns 2.
It sounds like you can break this into two easier problems.
How do you find the last digit of a given number?
How do you strip off the last digit of a given number?
Here's my solution. However, what are you supposed to do if there are no even digits in the number?
int findLastEvenDigit(int n)
{
lastDigit = n % 10;
if (lastDigit % 2 == 0) return lastDigit;
else return findLastEvenDigit(n/10);
}
Assumptions: No negative numbers (not sure/relevant if it will work for them)