c++ string (int) + string (int) [duplicate] - c++

This question already has answers here:
How to implement big int in C++
(14 answers)
Closed 9 years ago.
I have 2 strings, both contain only numbers. Those numbers are bigger than max of uint64_t.
How can I still add these 2 numbers and then convert the result to string?

Well, you can either use a bigger datatype (for example a library that deals with large integers), or you can quickly knock up your own.
I would suggest that if this is a one off, you do long addition exactly like you would have learned to do in your first few years of school. You can operate directly on the two strings, add the columns, do the 'carry', and build another string containing the result. You can do all this without any conversion to or from binary.
Here. Just for fun, I knocked up a solution for you:
string Add( const string& a, const string& b )
{
// Reserve storage for the result.
string result;
result.reserve( 1 + std::max(a.size(), b.size()) );
// Column positions and carry flag.
int apos = a.size();
int bpos = b.size();
int carry = 0;
// Add columns
while( carry > 0 || apos > 0 || bpos > 0 )
{
if( apos > 0 ) carry += a[--apos] - '0';
if( bpos > 0 ) carry += b[--bpos] - '0';
result.push_back('0' + (carry%10));
carry /= 10;
}
// The result string is backwards. Reverse and return it.
reverse( result.begin(), result.end() );
return result;
}
Note that, for clarity, this code doesn't even attempt to handle errors. It also doesn't do negatives, but it's not hard to fix that.

You need a a BigInt implementation. You can find several different ones here.
Whatever BigInt implementation you choose, needs to have conversion to and from string (they usually do).

Here is the code for your question:
#include <iostream>
#include <string>
using namespace std;
string StrAdd(string a, string b) {
string::reverse_iterator rit_a = a.rbegin();
string::reverse_iterator rit_b = b.rbegin();
string c;
int val_c_adv = 0;
while(rit_a != a.rend() && rit_b != b.rend() ) {
int val_a_i = *rit_a - '0';
int val_b_i = *rit_b - '0';
int val_c_i = val_a_i + val_b_i + val_c_adv;
if(val_c_i >= 10 ) {
val_c_adv = 1;
val_c_i -= 10;
} else {
val_c_adv = 0;
}
c.insert(0,1, (char)(val_c_i+'0'));
++rit_a;
++rit_b;
}
if(rit_a == a.rend() ) {
while( rit_b != b.rend() ) {
int val_b_i = *rit_b - '0';
int val_c_i = val_b_i + val_c_adv;
if(val_c_i >= 10 ) {
val_c_adv = 1;
val_c_i -= 10;
} else {
val_c_adv = 0;
}
c.insert(0, 1, (char)(val_c_i+'0'));
++rit_b;
}
} else if( rit_b == b.rend() ) {
while( rit_a != a.rend() ) {
int val_a_i = *rit_a - '0';
int val_c_i = val_a_i + val_c_adv;
if(val_c_i >= 10 ) {
val_c_adv = 1;
val_c_i -= 10;
} else {
val_c_adv = 0;
}
c.insert(0, 1, (char)(val_c_i+'0'));
++rit_a;
}
}
return c;
}
int main() {
string res, a, b;
cout << "a=" << endl;
cin >> a;
cout << "b=" << endl;
cin >> b;
res = StrAdd(a, b);
cout << "Result=" << res << endl;
}

If you just want to handle positive numbers without having to worry about bringing in an entire bignum library like GMP (along with its tendency to just abort on out-of-memory errors, something I find unforgivable in a general purpose library), you can roll your own, something like:
static std::string add (const std::string& num1, const std::string& num2) {
// Make num1 the wider number to simplify further code.
int digit, idx1 = num1.length() - 1, idx2 = num2.length() - 1;
if (idx1 < idx2) return add (num2, num1);
// Initialise loop variables.
int carry = 0;
std::string res; // reserve idx1+2 chars if you want.
// Add digits from right until thinner number finished.
while (idx2 >= 0) {
digit = num1[idx1--] - '0' + num2[idx2--] - '0' + carry;
carry = (digit > 9);
res.insert (0, 1, (digit % 10) + '0');
}
// Then just process rest of wider number and any leftover carry.
while (idx1 >= 0) {
digit = num1[idx1--] - '0' + carry;
carry = (digit > 9);
res.insert (0, 1, (digit % 10) + '0');
}
if (carry) res.insert (0, 1, '1');
return res;
}
You can add efficiencies like reserving space in the target string in advance, and setting specific indexes of it rather than inserting but, unless you're handling truly massive strings or doing it many time per second, I usually prefer code that is simpler to understand and maintain .

Related

How to multiply std::vector<int> by int where vector's each element should be one digit?

I have a class, call it 'BigNumber', which has a vector v field.
Each element should be one digit.
I want to implement a method to multiply this vector by an integer, but also keep elements one digit.
E.g: <7,6> * 50 = <3,8,0,0>
The vector represents a number, stored in this way. In my example, <7,6> is equal to 76, and <3,8,0,0> is 3800.
I tried the following, but this isn't good (however it works), and not the actual solution for the problem.
//int num, BigNumber bn
if (num > 0)
{
int value = 0, curr = 1;
for (int i = bn.getBigNumber().size() - 1; i >= 0; i--)
{
value += bn.getBigNumber().at(i) * num * curr;
curr *= 10;
}
bn.setBigNumber(value); //this shouldn't be here
return bn;
}
The expected algortithm is multiply the vector itself, not with a variable what I convert to this BigNumber.
The way I set Integer to BigNumber:
void BigNumber::setBigNumber(int num)
{
if (num > 0)
{
bigNum.clear();
while (num != 0)
{
bigNum.push_back(num % 10);
num = (num - (num % 10)) / 10;
}
std::reverse(bigNum.begin(), bigNum.end());
}
else
{
throw TOOSMALL;
}
};
The method I want to implement:
//class BigNumber{private: vector<int> bigNum; ... }
void BigNumber::multiplyBigNumber(BigNumber bn, int num)
{
if (num > 0)
{
//bn.bigNum * num
}
else
{
throw TOOSMALL;
}
}
As this is for a school project, I don't want to just write the code for you. So here's a hint.
Let's say you give me the number 1234 --- and I choose to store each digit in a vector in reverse. So now I've got bignum = [4, 3, 2, 1].
Now you ask me to multiply that by 5. So I create a new, empty vector result=[ ]. I look at the first item in bignum. It's a 4.
4 * 5 is 20, or (as you do at school) it is 0 carry 2. So I push the 0 into result, giving result = [0] and carry = 2.
Questions for you:
If you were doing this by hand (on paper), what would you do next?
Why did I decide to store the digits in reverse order?
Why did I decide to use a new vector (result), rather than modifying bignum?
and only after you have a worked out how to multiply a bignum by an int:
How would you multiply two bignums together?
The solutin for the problem is the follow code. I don't know if I can make this algorithm faster, but it works, so I'm happy with it.
BigNumber BigNumber::multiplyBigNumber(BigNumber bn, int num){
if (num > 0)
{
std::vector<int> result;
std::vector<int> rev = bn.getBigNumber();
std::reverse(rev.begin(),rev.end());
int carry = 0;
for(int i = 0; i<rev.size(); i++){
result.push_back((rev[i] * num + carry) % 10);
carry = (rev[i] * num + carry) / 10;
if(i == rev.size()-1 && carry / 10 == 0 && carry % 10 != 0 ) {
result.push_back(carry);
carry = carry / 10;
}
}
while((carry / 10) != 0){
result.push_back(carry % 10);
carry /= 10;
if(carry / 10 == 0) result.push_back(carry);
}
std::reverse(result.begin(),result.end());
bn.setBigNumber(result);
return bn;
}else{
throw TOOSMALL;
}
}

How to store in a string and convert to character array?

Write a C++ program to perform addition of two hexadecimal numerals which are less than 100 digits long. Use arrays to store hexadecimal numerals as arrays of characters.the solution is to add the corresponding digits in the format of hexadecimal directly. From right to left, add one to the digit on the left if the sum of the current digits exceed 16. You should be able to handle the case when two numbers have different digits.
The correct way to get the input is to store as character array. You can either first store in a string and convert to character array, or you can use methods such as cin.getline(), getc(), cin.get() to read in the characters.
I don't know what is wrong with my program and it I don't know how to use the function getline() and eof()
char a[number1],b[number1],c[number2],h;
int m,n,p(0),q(0),k,d[number1],z[number1],s[number2],L,M;
cout<<"Input two hexadecimal numerals(both of them within 100 digits):\n";
cin.getline(a,100);
cin.getline(b,100);
int x=strlen(a) ;
int y=strlen(b);
for(int i=0;i<(x/2);i++)
{
m=x-1-i;
h=a[i];
a[i]=a[m];
a[m]=h;
}
for(int j=0;j<(y/2);j++)
{
n=y-1-j;
h=b[j];
b[j]=b[n];
b[n]=h;
}
if(x>y)
{
for(int o=0;o<x;o++)//calculate a add b
{
if(o>=(y-1))
z[o]=0;//let array b(with no character)=0
if(a[o]=='A')
d[o]=10;
else if(a[o]=='B')
d[o]=11;
else if(a[o]=='C')
d[o]=12;
else if(a[o]=='D')
d[o]=13;
else if(a[o]=='E')
d[o]=14;
else if(a[o]=='F')
d[o]=15;
else if(a[o]=='0')
d[o]=0;
else if(a[o]=='1')
d[o]=1;
else if(a[o]=='2')
d[o]=2;
else if(a[o]=='3')
d[o]=3;
else if(a[o]=='4')
d[o]=4;
else if(a[o]=='5')
d[o]=5;
else if(a[o]=='6')
d[o]=6;
else if(a[o]=='7')
d[o]=7;
else if(a[o]=='8')
d[o]=8;
else if(a[o]=='9')
d[o]=9;
if(b[o]=='A')
z[o]=10;
else if(b[o]=='B')
z[o]=11;
else if(b[o]=='C')
z[o]=12;
else if(b[o]=='D')
z[o]=13;
else if(b[o]=='E')
z[o]=14;
else if(b[o]=='F')
z[o]=15;
else if(b[o]=='0')
z[o]=0;
else if(b[o]=='1')
z[o]=1;
else if(b[o]=='2')
z[o]=2;
else if(b[o]=='3')
z[o]=3;
else if(b[o]=='4')
z[o]=4;
else if(b[o]=='5')
z[o]=5;
else if(b[o]=='6')
z[o]=6;
else if(b[o]=='7')
z[o]=7;
else if(b[o]=='8')
z[o]=8;
else if(b[o]=='9')
z[o]=9;
p=d[o]+z[o]+q;
if(p>=16)//p is the remained number
{
q=1;
p=p%16;
}
else
q=0;
if(p==0)
c[o]='0';
else if(p==1)
c[o]='1';
else if(p==2)
c[o]='2';
else if(p==3)
c[o]='3';
else if(p==4)
c[o]='4';
else if(p==5)
c[o]='5';
else if(p==6)
c[o]='6';
else if(p==7)
c[o]='7';
else if(p==8)
c[o]='8';
else if(p==9)
c[o]='9';
else if(p==10)
c[o]='A';
else if(p==11)
c[o]='B';
else if(p==12)
c[o]='C';
else if(p==13)
c[o]='D';
else if(p==14)
c[o]='E';
else if(p==15)
c[o]='F';
}
k=x+1;
if(q==1)//calculate c[k]
{
c[k]='1';
for(int f=0;f<=(k/2);f++)
{
m=k-f;
h=c[f];
c[f]=c[m];
c[m]=h;
}
}
else
{
for(int e=0;e<=(x/2);e++)
{
m=x-e;
h=c[e];
c[e]=c[m];
c[m]=h;
}
}
}
if(x=y)
{
for(int o=0;o<x;o++)//calculate a add b
{
if(a[o]=='A')
d[o]=10;
else if(a[o]=='B')
d[o]=11;
else if(a[o]=='C')
d[o]=12;
else if(a[o]=='D')
d[o]=13;
else if(a[o]=='E')
d[o]=14;
else if(a[o]=='F')
d[o]=15;
else if(a[o]=='0')
d[o]=0;
else if(a[o]=='1')
d[o]=1;
else if(a[o]=='2')
d[o]=2;
else if(a[o]=='3')
d[o]=3;
else if(a[o]=='4')
d[o]=4;
else if(a[o]=='5')
d[o]=5;
else if(a[o]=='6')
d[o]=6;
else if(a[o]=='7')
d[o]=7;
else if(a[o]=='8')
d[o]=8;
else if(a[o]=='9')
d[o]=9;
if(b[o]=='A')
z[o]=10;
else if(b[o]=='B')
z[o]=11;
else if(b[o]=='C')
z[o]=12;
else if(b[o]=='D')
z[o]=13;
else if(b[o]=='E')
z[o]=14;
else if(b[o]=='F')
z[o]=15;
else if(b[o]=='0')
z[o]=0;
else if(b[o]=='1')
z[o]=1;
else if(b[o]=='2')
z[o]=2;
else if(b[o]=='3')
z[o]=3;
else if(b[o]=='4')
z[o]=4;
else if(b[o]=='5')
z[o]=5;
else if(b[o]=='6')
z[o]=6;
else if(b[o]=='7')
z[o]=7;
else if(b[o]=='8')
z[o]=8;
else if(b[o]=='9')
z[o]=9;
p=d[o]+z[o]+q;
M=p;
if(p>=16)
{
q=1;
p=p%16;
}
else
q=0;
s[o]=p;
if(p==0)
c[o]='0';
else if(p==1)
c[o]='1';
else if(p==2)
c[o]='2';
else if(p==3)
c[o]='3';
else if(p==4)
c[o]='4';
else if(p==5)
c[o]='5';
else if(p==6)
c[o]='6';
else if(p==7)
c[o]='7';
else if(p==8)
c[o]='8';
else if(p==9)
c[o]='9';
else if(p==10)
c[o]='A';
else if(p==11)
c[o]='B';
else if(p==12)
c[o]='C';
else if(p==13)
c[o]='D';
else if(p==14)
c[o]='E';
else if(p==15)
c[o]='F';
}
k=x+1;
if(q==1)
{
c[k]='1';
for(int f=0;f<=(k/2);f++)
{
m=k-f;
h=c[f];
c[f]=c[m];
c[m]=h;
}
}
else
{
for(int e=0;e<=(x/2);e++)
{
m=x-e;
h=c[e];
c[e]=c[m];
c[m]=h;
}
}
}
Lets look at what cin.getline does:
Extracts characters from stream until end of line. After constructing
and checking the sentry object, extracts characters from *this and
stores them in successive locations of the array whose first element
is pointed to by s, until any of the following occurs (tested in the
order shown):
end of file condition occurs in the input sequence (in which case setstate(eofbit) is executed)
the next available character c is the delimiter, as determined by Traits::eq(c, delim). The delimiter is extracted (unlike basic_istream::get()) and counted towards gcount(), but is not stored.
count-1 characters have been extracted (in which case setstate(failbit) is executed).
If the function extracts no characters (e.g. if count < 1), setstate(failbit)
is executed. In any case, if count>0, it then stores a null character
CharT() into the next successive location of the array and updates
gcount().
The result of that is in all cases, s now points to a null terminated string, of at most count-1 characters.
In your usage, you have up to 99 digits, and can use strlen to count exactly how many. eof is not a character, nor it is a member function of char.
You then reverse in place the inputs, and go about your overly repetitious conversions.
However, it's much simpler to use functions, both those you write yourself and those provided by the standard.
// translate from '0' - '9', 'A' - 'F', 'a' - 'f' to 0 - 15
static std::map<char, int> hexToDec { { '0', 0 }, { '1', 1 }, ... { 'f', 15 }, { 'F', 15 } };
// translate from 0 - 15 to '0' - '9', 'A' - 'F'
static std::map<int, char> decToHex { { 0, '0' }, { 1, '1' }, ... { 15, 'F' } };
std::pair<char, bool> hex_add(char left, char right, bool carry)
{
// translate each hex "digit" and add them
int sum = hexToDec[left] + hexToDec[right];
// we have a carry from the previous sum
if (carry) { ++sum; }
// translate back to hex, and check if carry
return std::make_pair(decToHex[sum % 16], sum >= 16);
}
int main()
{
std::cout << "Input two hexadecimal numerals(both of them within 100 digits):\n";
// read two strings
std::string first, second;
std::cin >> first >> second;
// reserve enough for final carry
std::string reverse_result(std::max(first.size(), second.size()) + 1, '\0');
// traverse the strings in reverse
std::string::const_reverse_iterator fit = first.rbegin();
std::string::const_reverse_iterator sit = second.rbegin();
std::string::iterator rit = reverse_result.begin();
bool carry = false;
// while there are letters in both inputs, add (with carry) from both
for (; (fit != first.rend()) && (sit != second.rend()); ++fit, ++sit, ++rit)
{
std::tie(*rit, carry) = hex_add(*fit, *sit, carry);
}
// now add the remaining digits of first (will do nothing if second is longer)
for (; (fit != first.rend()); ++fit)
{
// we need to account for a carry in the last place
// potentially all the way up if we are adding e.g. "FFFF" to "1"
std::tie(*rit, carry) = hex_add(*fit, *rit++, carry);
}
// or add the remaining digits of second
for (; (sit != second.rend()); ++sit)
{
// we need to account for a carry in the last place
// potentially all the way up if we are adding e.g. "FFFF" to "1"
std::tie(*rit, carry) = hex_add(*sit, *rit++, carry);
}
// result has been assembled in reverse, so output it reversed
std::cout << reverse_result.reverse();
}
Regarding the text of your problem: “add one to the digit on the left if the sum of the current digits exceed 16” is wrong; it should be 15, not 16.
Regarding your code: I did not have the patience to read all your code, however:
I have noticed one long if/else. Use a switch (but you do not need one).
To find out if a character is a hex digit use isxdigit (#include <cctype>).
The user might input uppercase and lowercase characters: convert them to the same case using toupper/tolower.
To convert a hex digit to an integer:
if the digit is between ‘0’ and ‘9’ simply subtract ‘0’. This works because the codes for ‘0’, ‘1’… are 0x30, 0x31... (google ASCII codes).
if the digit is between ‘A’ and ‘F’, subtract ‘A’ and add 10.
Solving the problem:
“less than 100 digits long” This is a clear indication regarding how your data must be stored: a simple 100 long array, no std::string, no std::vector:
#define MAX_DIGITS 100
typedef int long_hex_t[MAX_DIGITS];
In other words your numbers are 100 digits wide, at most.
Decide how you store the number: least significant digit first or last? I would chose to store the least significant first. 123 is stored as {3,2,1,0,…0}
Use functions to simplify your code. You will need three functions: read, print and add:
int main()
{
long_hex_t a;
read( a );
long_hex_t b;
read( b );
long_hex_t c;
add( c, a, b );
print( c );
return 0;
}
The easiest function to write is add followed by print and read.
For read use get and putback to analyze the input stream: get extracts the next character from stream and putback is inserting it back in stream (if we do not know how to handle it).
Here it is a full solution (try it):
#include <iostream>
#include <cctype>
#define MAX_DIGITS 100
typedef int long_hex_t[MAX_DIGITS];
void add( long_hex_t c, long_hex_t a, long_hex_t b )
{
int carry = 0;
for ( int i = 0; i < MAX_DIGITS; ++i )
{
int t = a[i] + b[i] + carry;
c[i] = t % 16;
carry = t / 16;
}
}
void print( long_hex_t h )
{
//
int i;
// skip leading zeros
for ( i = MAX_DIGITS - 1; i >= 0 && h[i] == 0; --i )
;
// all zero
if ( i < 0 )
{
std::cout << '0';
return;
}
// print remaining digits
for ( i; i >= 0; --i )
std::cout << char( h[i] < 10 ? h[i] + '0' : h[i] - 10 + 'A' );
}
void read( long_hex_t h )
{
// skip ws
std::ws( std::cin );
// skip zeros
{
char c;
while ( std::cin.get( c ) && c == '0' )
;
std::cin.putback( c );
}
//
int count;
{
int i;
for ( i = 0; i < MAX_DIGITS; ++i )
{
char c;
if ( !std::cin.get( c ) )
break;
if ( !std::isxdigit( c ) )
{
std::cin.putback( c );
break;
}
c = std::toupper( c );
h[i] = c <= '9'
? ( c - '0' )
: ( c - 'A' + 10 );
}
count = i;
}
// reverse
for ( int i = 0, ri = count - 1; i < count / 2; ++i, --ri )
{
int t = h[i];
h[i] = h[ri];
h[ri] = t;
}
// fill the rest with zero
for ( int i = count; i < MAX_DIGITS; ++i )
h[i] = 0;
}
int main()
{
long_hex_t a;
read( a );
long_hex_t b;
read( b );
long_hex_t c;
add( c, a, b );
print( c );
return 0;
}
This is a long answer. Because you have much bug in your code. Your using of getline is ok. But your are calling a eof() like e.eof() which is wrong. If you have looked at your compilation error, you would see that it was complaining about calling eof() on the variable e because it is of non-class type. Simple meaning it is not an object of some class. You cannot put the dot operator . on primitive types like that. I think what you are wanting to do, is to terminate the loop when you have reached the end of line. So that index1 and index2 can get the length of the string input. If I were you, I would just use C++ builtin strlen() function for that. And in the first place, you should use C++ class string to handle strings. Also strings have a null - terminating character '\0' at the end of them. If you don't know about it, I suggest you take some time to read about strings.
Secondly, you have many bugs and errors in your code. The way you are reversing your string is not correct. Ask yourself, what are the contents of the arrays a and b at position which have higher index than the length of the string? You should use reverse() for reversing strings and arrays.
You have errors on adding loop also. Note, you are changing the arrays value when they are A, B, C, D, and so on for hexadecimal values with the corresponding decimal values 10,11,12,13 and so on. But you should change the values for the character '0' - '9' also. Because when the array holds '0' it is not integer 0. But is is ASCII '0' which has integer value of 48. And the character '1' has integer value of 49 and so on. You want to replace this values with corresponding integer values also. When you are also storing the result values in c, you are only handling only those values which are above 9 and replacing them with corresponding characters. You should also replace the integers 0 - 9 with there corresponding ASCII characters. Also don't forget to put a null terminating character at the end of the result.
Also, when p is getting larger than 15, you are only changing your carry, but you should also change p accordingly.
I believe you can reverse the result array c in a much more elegant way. By only reversing when the calculation has been performed totally. You can simple call reverse() for that.
I believe you can think hard a little bit more, and write the code in the right way. I have a few suggestions for you, don't use variable names like a,b,c,o. Try to name variables with what are they really doing. Also, you can improve your algorithm and shorten your code and headache with one simple change in the algorithm. First find the length of a and then find the length of b. If there lengths are unequal, find out which has lesser length. Then add 0s in front of it to make both lengths equal. Now, you can simply start from the back, and perform the addition. Also, you should use builtin methods like reverse() , swap() and also string class to make your life easier ;)
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main(){
string firstVal,secondVal;
cout<<"Input two hexadecimal numerals(both of them within 100 digits):\n";
cin >> firstVal >> secondVal;
//Adjust the length.
if(firstVal.size() < secondVal.size()){
//Find out the number of leading zeroes needed
int leading_zeroes = secondVal.size() - firstVal.size();
for(int i = 0; i < leading_zeroes; i++){
firstVal = '0' + firstVal;
}
}
else if(firstVal.size() > secondVal.size()){
int leading_zeroes = firstVal.size() - secondVal.size();
for(int i = 0; i < leading_zeroes; i++){
secondVal = '0' + secondVal;
}
}
// Now, perform addition.
string result;
int digit_a,digit_b,carry=0;
for(int i = firstVal.size()-1; i >= 0; i--){
if(firstVal[i] >= '0' && firstVal[i] <= '9') digit_a = firstVal[i] - '0';
else digit_a = firstVal[i] - 'A' + 10;
if(secondVal[i] >= '0' && secondVal[i] <= '9') digit_b = secondVal[i] - '0';
else digit_b = secondVal[i] - 'A' + 10;
int sum = digit_a + digit_b + carry;
if(sum > 15){
carry = 1;
sum = sum % 16;
}
else{
carry = 0;
}
// Convert sum to char.
char char_sum;
if(sum >= 0 && sum <= 9) char_sum = sum + '0';
else char_sum = sum - 10 + 'A';
//Append to result.
result = result + char_sum;
}
if(carry > 0) result = result + (char)(carry + '0');
//Result is in reverse order.
reverse(result.begin(),result.end());
cout << result << endl;
}

Manually converting string to int and check if an overflow occured in C/C++?

I have the following issue - I wrote a function that takes a string and converts it to an int, but I don't know how to check if any overflow occurs. I want to return the last possible value of the integer, before the overflow ocurred.
For example: if I have a string representation of "2147483648", I want to return 214748364 as an int, because in the next iterration an overflow will occur. Do you have any ideas how to solve this?
My code is:
int main () {
string s = "2147483647";
int num = 0, i = 0, buff = 0;
bool isNegative = false;
if (s[0] == '-') {
isNegative = true;
i++;
}
while (i < s.length()) {
if (num < (INT_MAX/10)) {
num *= 10;
}
if (num < INT_MAX - 10)
num += s[i++] - '0';
else
break;
}
if (isNegative)
num = -num;
cout << "\nthe number is: " << num;
getch();
return 0;
}
To cope with int overflow, code must prevent it.
Simple test if num and digit are too big before attempting num*10 + digit
(num >= INT_MAX/10) && ((num > INT_MAX/10) || (digit > INT_MAX%10))
Usage
overflow = false;
while (i < s.length()) {
int digit = s[i++] - '0';
// Will num*10 + digit overflow?
if ((num >= INT_MAX/10) && ((num > INT_MAX/10) || (digit > INT_MAX%10))) {
// or break per OP's coding goal
num = INT_MAX;
overflow = true;
} else {
num *= 10;
num += digit;
}
}
OP's code also has trouble with the textual version of INT_MIN.
Sample my_atoi() that correctly returns [INT_MIN ... INT_MAX]
I see two possible solutions:
1) Check if num<(INT_MAX/10) before multiplying num with 10 and check that num < INT_MAX - 10 before adding s[i++]. You will need to include limits.h for this.
2) After converting your string to an int, use snprintf to print your int back to a string and use strcmp to see if your strings are identical.
Your best bet is using stoi instead of hand-crafting an inferior solution.
try {
i = stoi(s);
} catch(const out_of_range& /*e*/) {
i = numeric_limits<int>::max();
}
Live Example

Stuck in an infinite loop? (Maybe)

I am trying to complete Project Euler Problem 14 in c++ and I am honestly stuck. Right now when I run the problem it gets stuck at So Far: the number with the highest count: 113370 with the count of 155
So Far: the number with the highest count but when I try changing the i value to over 113371 it works. What is going on??
The question is:
The following iterative sequence is defined for the set of positive
integers: n → n/2 (n is even) n → 3n + 1 (n is odd)
Using the rule above and starting with 13, we generate the following
sequence:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 It can be seen that this
sequence (starting at 13 and finishing at 1) contains 10 terms.
Although it has not been proved yet (Collatz Problem), it is
thought that all starting numbers finish at 1. Which starting number,
under one million, produces the longest chain?
#include<stdio.h>
int main() {
int limit = 1000000;
int highNum, number, i;
int highCount = 0;
int count = 0;
for( number = 13; number <= 1000000; number++ )
{
i = number;
while( i != 1 ) {
if (( i % 2 ) != 0 ) {
i = ( i * 3 ) + 1;
count++;
}
else {
count++;
i /= 2;
}
}
count++;
printf( "So Far: the number with the highest count: %d with the count of %d\n",
number, count );
if( highCount < count ) {
highCount = count;
highNum = number;
}
count = 0;
//break;
}
printf( "The number with the highest count: %d with the count of %d\n",
highNum, highCount );
}
You are getting integer overflow. Update your code like this and see it yourself:
if (( i % 2 ) != 0 ) {
int prevI = i;
i = ( i * 3 ) + 1;
if (i < prevI) {
printf("oops, i < prevI: %d\n", i);
return 0;
}
count++;
}
You should change the type of i to long long or unsigned long long to prevent the overflow.
(And yes, cache the intermediate results)
Remember all intermediate results (up to some suitably high number).
Also, use a big-enough type:
#include <stdio.h>
static int collatz[4000000];
unsigned long long collatzmax;
int comp(unsigned long long i) {
if(i>=sizeof collatz/sizeof*collatz) {
if(i>collatzmax)
collatzmax = i;
return 1 + comp(i&1 ? 3*i+1 : i/2);
}
if(!collatz[i])
collatz[i] = 1 + comp(i&1 ? 3*i+1 : i/2);
return collatz[i];
}
int main() {
collatz[1] = 1;
int highNumber= 1, highCount = 1, c;
for(int i = 2; i < 1000000; i++)
if((c = comp(i)) > highCount) {
highCount = c;
highNumber = i;
}
printf( "The number with the highest count: %d with the count of %d\n",
highNumber, highCount );
printf( "Highest intermediary number: %llu\n", collatzmax);
}
On coliru: http://coliru.stacked-crooked.com/a/773bd8c5f4e7d5a9
Variant with smaller runtime: http://coliru.stacked-crooked.com/a/2132cb74e4605d5f
The number with the highest count: 837799 with the count of 525
Highest intermediary number: 56991483520
BTW: The highest intermediary encountered needs 36 bit to represent as an unsigned number.
With your algorithm, you compute several time identical series.
you may cache result for previous numbers and reuse them.
Something like:
void compute(std::map<std::uint64_t, int>& counts, std::uint64_t i)
{
std::vector<std::uint64_t> series;
while (counts[i] == 0) {
series.push_back(i);
if ((i % 2) != 0) {
i = (i * 3) + 1;
} else {
i /= 2;
}
}
int count = counts[i];
for (auto it = series.rbegin(); it != series.rend(); ++it)
{
counts[*it] = ++count;
}
}
int main()
{
const std::uint64_t limit = 1000000;
std::map<std::uint64_t, int> counts;
counts[1] = 1;
for (std::size_t i = 2; i != limit; ++i) {
compute(counts, i);
}
auto it = std::max_element(counts.begin(), counts.end(),
[](const std::pair<std::uint64_t, int>& lhs, const std::pair<std::uint64_t, int>& rhs)
{
return lhs.second < rhs.second;
});
std::cout << it->first << ":" << it->second << std::endl;
std::cout << limit-1 << ":" << counts[limit-1] << std::endl;
}
Demo (10 seconds)
Don't recompute the same intermediate results over and over!
Given
typedef std::uint64_t num; // largest reliable built-in unsigned integer type
num collatz(num x)
{
return (x & 1) ? (3*x + 1) : (x/2);
}
Then the value of collatz(x) only depends on x, not on when you call it. (In other words, collatz is a pure function.) As a consequence, you can memoize the values of collatz(x) for different values of x. For this purpose, you could use a std::map<num, num> or a std::unordered_map<num, num>.
For reference, here is the complete solution.
And here it is on Coliru, with timing (2.6 secs).

How can I make my implementation of Project Euler 25 faster, so I can actually compute the answer?

Here is my implementation of Problem 25 - Project Euler (see comments in code for explanation of how it works):
#include <iostream> //Declare headers and use correct namespace
#include <math.h>
using namespace std;
//Variables for the equation F_n(newTerm) = F_n-1(prevTerm) + Fn_2(currentTerm)
unsigned long long newTerm = 0;
unsigned long long prevTerm = 1; //F_1 initially = 1
unsigned long long currentTerm = 1; //F_2 initially = 2
unsigned long long termNo = 2; //Current number for the term
void getNextTerms() { //Iterates through the Fib sequence, by changing the global variables.
newTerm = prevTerm + currentTerm; //First run: newTerm = 2
unsigned long long temp = currentTerm; //temp = 1
currentTerm = newTerm; //currentTerm = 2
prevTerm = temp; //prevTerm = 1
termNo++; //termNo = 3
}
unsigned long long getLength(unsigned long long number) //Returns the length of the number
{
unsigned long long length = 0;
while (number >= 1) {
number = number / 10;
length++;
}
return length;
}
int main (int argc, const char * argv[])
{
while (true) {
getNextTerms(); //Gets next term in the Fib sequence
if (getLength(currentTerm) < 1000) { //Checks if the next terms size is less than the desired length
}
else { //Otherwise if it is perfect print out the term.
cout << termNo;
break;
}
}
}
This works for the example, and will run quickly as long as this line:
if (getLength(currentTerm) < 1000) { //Checks if the next term's size is less than the desired length
says 20 or lower instead of 1000. But if that number is greater than 20 it takes a forever, my patience gets the better of me and I stop the program, how can I make this algorithm more efficient?
If you have any questions just ask in the comments.
There is a closed formula for the Fibonachi numbers (as well as for any linear recurrent sequence).
So F_n = C1 * a^n + C2 * b^n, where C1, C2, a and b are numbers that can be found from the initial conditions, i.e. for the Fib case from
F_n+2 = F_n+1 + F_n
F_1 = 1
F_2 = 1
I don't give their values on purpose here. It's just a hint.
nth fibonacci number is =
(g1^n-g2^n)/sqrt(5).
where g1 = (1+sqrt(5))/2 = 1.61803399
g2 = (1-sqrt(5))/2 = -0.61803399
For finding the length of nth fibonacci number, we can just calculate the log(nth fibonacci number).So, length of nth fibonacci number is,
log((g1^n-g2^n)/sqrt(5)) = log(g1^n-g2^n)-0.5*log(5).
you can just ignore g2^n, since it is very small negative number.
Hence, length of nth fibonacci is
n*log(g1)-0.5*log(5)
and we need to find the smallest value of 'n' such that this length = 1000, so we can find the value of n for which the length is just greater than 999.
So,
n*log(g1)-0.5*log(5) > 999
n*log(g1) > 999+0.5*log(5)
n > (999+0.5*log(5))/log(g1)
n > (999.3494850021680094)/(0.20898764058551)
n > 4781.859263075
Hence, the smallest required n is 4782. No use of any coding, easiest way.
Note: everywhere log is used in base 10.
This will probably speed it up a fair bit:
int getLength(unsigned long long number) //Returns the length of the number when expressed in base-10
{
return (int)log10(number) + 1;
}
...but, you can't reach 1000 digits using an unsigned long long. I suggest looking into arbitrary-precision arithmetic libraries, or languages which have arbitrary-precision arithmetic built in.
You could try computing a Fibonacci number using matrix exponentiation. Then repeated doubling to get to a number that has more than 1000 digits and use binary search in that range to find the first one.
using doubles, you can come to a solution knowing the highest exponential is 308:
get the sequence to the exp of 250, then divide your two numbers by 1e250. Restart the algorithm with those two numbers
if you do this 4 times, you'll get the right answer
C++ code maybe as follows:
#include "iostream"
#include "string.h"
#include "algorithm"
using namespace std;
string addTwoString(string a, string b)
{
if (a.length() == 0)
{
return b;
}
if (b.length() == 0)
{
return a;
}
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
string result = "";
string str_1, str_2;
if (a.length() > b.length())
{
str_1 = b;
str_2 = a;
}
else
{
str_1 = a;
str_2 = b;
}
int index = 0;
int value = 0, over_value = 0;
for (; index < str_1.length(); ++index)
{
int temp_1 = (int)(str_1[index] - '0');
int temp_2 = (int)(str_2[index] - '0');
int temp = temp_1 + temp_2 + over_value;
value = temp % 10;
over_value = temp / 10;
char c = (char)(value + '0');
result += c;
}
for (; index < str_2.length(); ++index)
{
int temp_2 = (int)(str_2[index] - '0');
int temp = temp_2 + over_value;
value = temp % 10;
over_value = temp / 10;
char c = (char)(value + '0');
result += c;
}
if (over_value > 0)
{
char c = (char)(over_value + '0');
result += c;
}
reverse(result.begin(), result.end());
return result;
}
int main()
{
string a = "1";
string b = "1";
string c = addTwoString(a, b);
int index = 3;
while (c.length() < 1000)
{
a = b;
b = c;
c = addTwoString(a, b);
++ index;
}
cout << index << endl;
}
I just used a recursive function that adds arrays vertically to complete the problem. Basically zero run time, less than 50 lines of code. Enjoy:
#include <stdio.h>
int Calc_Fib (int numA[], int numB[], int temp[], int index) {
int i = 0;
//Check 1000th digit for non-zero value.
if (numB[999] != 0) return index;
//Add arrays A and B vertically.
for (i = 0; i < 1000; ++i) {
temp[i] += (numA[i] + numB[i]);
if (temp[i] > 9) {
temp[i + 1] = temp[i] / 10;
temp[i] %= 10;
}
numA[i] = numB[i];
numB[i] = temp[i];
temp[i] = 0;
}
Calc_Fib(numA, numB, temp, ++index);
}
int main() {
int numA[1000]; //Holds previous term.
int numB[1000]; //Holds current term.
int temp[1000]; //Holds temporary number for vertical addition.
int i = 0;
int indexVal = 2;
for (i = 0; i < 1000; ++i) {
numA[i] = 0;
numB[i] = 0;
temp[i] = 0;
}
//Initialize first two terms.
numA[0] = (numB[0] = 1);
indexVal = Calc_Fib(numA, numB, temp, indexVal);
printf("Tada: %d\n", indexVal);
return 0;
}