my value is more than the range of unsigned integer - c++

i have this exercise:" consider some natural number n, if it is not a Palindrom number, change the order of the digits in reverse order and add the resulting number with the original number. If the sum is not a palindrom number, repeat the same procedure on that sum until a palindrom number is obtained. Whether the above process is finite for any n. If yes, print out the number of process "
ex
input:1 output: 0
input: 12 output: 1
my problem is when i encounter larger number such as 19170 it will be over the limit of unsigned long long int
It will also be great if anyone can explain or guide me to resources that can help me understand it further.
#include <iostream>
#include <math.h>
using namespace std;
bool check (long long int n)
{
long long int clone_n=n,count=0,ans=0;
while (clone_n!=0)
{
clone_n/=10;
count++;
}
clone_n=n;
for(int i=count;i>=0;i--)
{
ans+=(clone_n%10)*pow(10,i-1);
clone_n/=10;
}
if(ans==n)
{
return true;
}
return false;
}
long long int reverse(long long int n)
{
long long int clone_n=n,count=0,ans=0;
while (clone_n!=0)
{
clone_n/=10;
count++;
}
clone_n=n;
for(int i=count;i>=0;i--)
{
ans+=(clone_n%10)*pow(10,i-1);
clone_n/=10;
}
return ans;
}
int main()
{
long long int n,count=0;
cin>>n;
if(check(n))
{
cout<<0;
return 0;
}
else
{
while(check(n)!=1)
{
count++;
n+=reverse(n);
}
}
cout<<count;
}
my code is also included in the link: https://ideone.com/0p7JJU

The natural number that will not terminate the algorithm that the OP describe is called Lychrel number. https://en.wikipedia.org/wiki/Lychrel_number
It is currently unknown if any of these number exists, as correctly guessed by zkoza in the above answer, 196 is the smallest candidate to be a Lychrel number.
So, this is a specifically hard problem to tackle, however, I would like to address the specific overflow issue that the OP is facing. As pointed out by largest_prime_is_463035818 in the comments, there is no actual needs of any integer representation.
#include <iostream>
//take advantage of the fact that std::string use contiguous memory
bool is_palindrome(const char* first, const char* last)
{
--last;
while(first < last) {
if (*first != *last)
return false;
++first;
--last;
}
return true;
}
std::string reverse_and_add(const std::string& digits)
{
size_t size = digits.size();
//the result string will be at least the same length
std::string result(size,'0');
int carry_over = 0;
int ascii_zero = 48;
for (size_t i = 0; i < size; i++)
{
int front = digits.at(i) - ascii_zero;
int back = digits.at(size - i - 1) - ascii_zero;
int sum = front + back + carry_over;
carry_over = sum / 10;
int digit = sum >= 10 ? sum - 10 : sum;
result[size - i - 1] = static_cast<char>(digit + ascii_zero);
}
//if at the last step we have a carry over we need to add an extra digit to
//the string
if (carry_over > 0)
result = static_cast<char>(carry_over + ascii_zero) + result;
return result;
}
void check(const std::string& s, int max_iteration)
{
int counter = 0;
std::string v(s);
while(!is_palindrome(v.c_str(), v.c_str() + v.size()) && counter < max_iteration)
{
v = reverse_and_add(v);
if (counter % 1000 == 0 && counter > 0)
std::cout << "progressing iteration: " << counter << " string size: " << v.size() << std::endl;
counter++;
}
if (counter == max_iteration)
std::cout << "No result found" << std::endl;
else
std::cout << "result: " << counter << std::endl;
}
int main()
{
int max_iteration = 50000;
check("187",max_iteration); // -> return 23
check("19170", max_iteration); // -> doesn't find a solution
// the final string is thousands of characters
}
UPDATE
Just for fun, I run 196 till 1000000 digits (that it took 3 years to complete 1987) and it produce the same result in about an hour and half (these hardware engineers are amazing).
result: 2415836
./a.out 5315.83s user 21.29s system 99% cpu 1:29:12.58 total

I assume this is a homework question.
The first number for which the sequence does not seem to be finite is as small as 196. I terminated a program after it hit 300000 digits.
What can you do?
Write a similar program where you implement your own "big numbers". It's an easy task, because all you need is addition of two same-length numbers, reversal, checking for being a palindrom, perhaps printing. You can use std::vector or std::string.
Then, introduce an ad hoc threshold, like 100 or 1000 iterations. If the sequence will reach the threshold, stop it and return false.
It is possible that you did not present here the complete, detailed description of the problem. I found a similar problem on the internet, but with an explicit threshold of 5 iterations. Or perhaps it is a problem that you've invented yourself, unaware of its complexity? Or the teacher is pulling your leg? Or I made a mistake in my code.
A famous example of a problem that has a simple formulation but no known solution is the Collatz conjecture, https://en.wikipedia.org/wiki/Collatz_conjecture . It can't be ruled out that your problem is of a similar type.
Here, for reference, is my solution for numbers from 180 to 195 (the first number in the sequence, the number of iteration, the last number in the sequence)
180 3 747
181 0 181
182 6 45254
183 4 13431
184 3 2552
185 3 4774
186 3 6996
187 23 8813200023188
188 7 233332
189 2 1881
190 7 45254
191 0 191
192 4 6996
193 8 233332
194 3 2992
195 4 9339

Instead of numeric data type you can use string to store the values and do addition by parsing the whole string like this
#include <iostream>
#include <string>
int main()
{
std::string s1 = "759579537575937593759387";
std::string s2 = "9956775659653876536535637653";
int n1=s1.size()-1,n2=s2.size()-1;
std::string s3 = "";
uint8_t carry = 0;
while(n1>=0 && n2>=0){
uint8_t num1 = (int)s1[n1--] - 48;
uint8_t num2 = (int)s2[n2--] - 48;
uint8_t sum = char(num1+num2) + carry;
carry = sum/10; // to get carry
sum = sum%10;
s3.insert(0,1,char(sum+48));
}
while(n1>=0)
{
uint8_t sum = carry + (int)s1[n1--] - 48;
carry = sum/10;
sum = sum%10;
s3.insert(0,1,char(sum+48));
}
while(n2>=0)
{
uint8_t sum = carry + (int)s2[n2--] - 48;
carry = sum/10;
sum = sum%10;
s3.insert(0,1,char(sum+48));
}
if (carry)
s3.insert(0,1,char(carry+48));
std::cout<<s3<<std::endl;
}
also you check if they are palindromic or not using two pointer method.
The above sum which I get is 9957535239191452474129397040, there is no limit to addition by this method

Related

Number of steps to reduce a number in binary representation to 1

Given the binary representation of an integer as a string s, return the number of steps to reduce it to 1 under the following rules:
If the current number is even, you have to divide it by 2.
If the current number is odd, you have to add 1 to it.
It is guaranteed that you can always reach one for all test cases.
Step 1) 13 is odd, add 1 and obtain 14.
Step 2) 14 is even, divide by 2 and obtain 7.
Step 3) 7 is odd, add 1 and obtain 8.
Step 4) 8 is even, divide by 2 and obtain 4.
Step 5) 4 is even, divide by 2 and obtain 2.
Step 6) 2 is even, divide by 2 and obtain 1.
My input = 1111011110000011100000110001011011110010111001010111110001
Expected output = 85
My output = 81
For the above input, the output is supposed to be 85. But my output shows 81. For other test cases it
seems to be giving the right answer. I have been trying all possible debugs, but I am stuck.
#include <iostream>
#include <string.h>
#include <vector>
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s =
"1111011110000011100000110001011011110010111001010111110001";
long int count = 0, size;
unsigned long long int dec = 0;
size = s.size();
// cout << s[size - 1] << endl;
for (int i = 0; i < size; i++)
{
// cout << pow(2, size - i - 1) << endl;
if (s[i] == '0')
continue;
// cout<<int(s[i])-48<<endl;
dec += (int(s[i]) - 48) * pow(2, size - 1 - i);
}
// cout << dec << endl;
// dec = 278675673186014705;
while (dec != 1)
{
if (dec % 2 == 0)
dec /= 2;
else
dec += 1;
count += 1;
}
cout << count;
return 0;
}
This line:
pow(2, size - 1 - i)
Can face precision errors as pow takes and returns doubles.
Luckily, for powers base 2 that won't overflow unsigned long longs, we can simply use bit shift (which is equivalent to pow(2, x)).
Replace that line with:
1LL<<(size - 1 - i)
So that it should look like this:
dec += (int(s[i]) - 48) * 1ULL<<(size - 1 - i);
And we will get the correct output of 85.
Note: as mentioned by #RSahu, you can remove (int(s[i]) - 48), as the case where int(s[i]) == '0' is already caught in an above if statement. Simply change the line to:
dec += 1ULL<<(size - 1 - i);
The core problem has already been pointed out in answer by #Ryan Zhang.
I want to offer some suggestions to improve your code and make it easier to debug.
The main function has two parts -- first part coverts a string to number and the second part computes the number of steps to get the number to 1. I suggest creating two helper functions. That will allow you to debug each piece separately.
int main()
{
string s = "1111011110000011100000110001011011110010111001010111110001";
unsigned long long int dec = stringToNumber(s);
cout << "Number: " << dec << endl;
// dec = 278675673186014705;
int count = getStepsTo1(dec);
cout << "Steps to 1: " << count << endl;
return 0;
}
Iterate over the string from right to left using std::string::reverse_iterator. That will obviate the need for size and use of size - i - 1. You can just use i.
unsigned long long stringToNumber(string const& s)
{
size_t i = 0;
unsigned long long num = 0;
for (auto it = s.rbegin(); it != s.rend(); ++it, ++i )
{
if (*it != '0')
{
num += 1ULL << i;
}
}
return num;
}
Here's the other helper function.
int getStepsTo1(unsigned long long num)
{
long int count = 0;
while (num != 1 )
{
if (num % 2 == 0)
num /= 2;
else
num += 1;
count += 1;
}
return count;
}
Working demo: https://ideone.com/yerRfK.

Kickstart 2022 interesting numbers

The question is to find the number of interesting numbers lying between two numbers. By the interesting number, they mean that the product of its digits is divisible by the sum of its digits.
For example: 459 => product = 4 * 5 * 9 = 180, and sum = 4 + 5 + 9 = 18; 180 % 18 == 0, hence it is an interesting number.
My solution for this problem is having run time error and time complexity of O(n2).
#include<iostream>
using namespace std;
int main(){
int x,y,p=1,s=0,count=0,r;
cout<<"enter two numbers"<<endl;
cin>>x>>y;
for(int i=x;i<=y;i++)
{
r=0;
while(i>1)
{
r=i%10;
s+=r;
p*=r;
i/=10;
}
if(p%s==0)
{
count++;
}
}
cout<<"count of interesting numbers are"<<count<<endl;
return 0;
}
If s is zero then if(p%s==0) will produce a divide by zero error.
Inside your for loop you modify the value of i to 0 or 1, this will mean the for loop never completes and will continuously check 1 and 2.
You also don't reinitialise p and s for each iteration of the for loop so will produce the wrong answer anyway. In general limit the scope of variables to where they are actually needed as this helps to avoid this type of bug.
Something like this should fix these problems:
#include <iostream>
int main()
{
std::cout << "enter two numbers\n";
int begin;
int end;
std::cin >> begin >> end;
int count = 0;
for (int number = begin; number <= end; number++) {
int sum = 0;
int product = 1;
int value = number;
while (value != 0) {
int digit = value % 10;
sum += digit;
product *= digit;
value /= 10;
}
if (sum != 0 && product % sum == 0) {
count++;
}
}
std::cout << "count of interesting numbers are " << count << "\n";
return 0;
}
I'd guess the contest is trying to get you to do something more efficient than this, for example after calculating the sum and product for 1234 to find the sum for 1235 you just need to add one and for the product you can divide by 4 then multiply by 5.

why for loop is not work correctly for a simple multiplication numbers 1 to 50?

code:
#include <iostream>
using namespace std;
int main() {
int answer = 1;
int i = 1;
for (; i <= 50; i++){
answer = answer * i;
}
cout << answer << endl;
return 0;
}
resault :
0
...Program finished with exit code 0
Press ENTER to exit console.
when i run this code in an online c++ compiler, it shows me zero(0) in console. why?
I will answer specifically the asked question "Why?" and not the one added in the comments "How?".
You get the result 0 because one of the intermediate values of answer is 0 and multiplying anything with it will stay 0.
Here are the intermediate values (I found them by moving your output into the loop.):
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
1932053504
1278945280
2004310016
2004189184
-288522240
-898433024
109641728
-2102132736
-1195114496
-522715136
862453760
-775946240
2076180480
-1853882368
1484783616
-1375731712
-1241513984
1409286144
738197504
-2147483648
-2147483648
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
E.g. here https://www.tutorialspoint.com/compile_cpp_online.php
Now to explain why one of them is 0 to begin with:
Because of the values, the sequence of faculties, quickly leaves the value range representable in the chosen data type (note that the number decimal digits does not increase at some point; though the binary digits are the relevant ones).
After that, the values are not really related to the correct values anymore, see them even jumping below zero and back...
... and one of them happens to be 0.
For the "How?" please see the comments (and maybe other, valuable answers).
Short Answer:
Your code is not working correctly because it performs 50 factorial, that the answer is 3.04*10^64. This number is greater than the int size, that is 2^31 - 1.
Long answer
You can check the problem logging the intermediate answers. This can help you to have some insights about the code situation. Here you can see that the number rotate from positive to negative, that's show the maximum possible multiplication with this code strategy.
https://onlinegdb.com/ycnNADKmX
The answer
30414093201713378043612608166064768844377641568960512000000000000
To archive the correct answer to any case of factorial, you need to have some strategy to operate to large numbers.
In fact, if you're working a large company, you probably have some library to work with large numbers. In this situation, is very important use this library to keep the code consistent.
In other hand, supposing that's an academic homework, you can choose any strategy in the Internet. In this situation I used the strategy that uses string to represent large numbers. You can see the solution here https://www.geeksforgeeks.org/multiply-large-numbers-represented-as-strings
The final program that compute the 50! in the proper manner using the string strategy to represent large numbers you can find here https://onlinegdb.com/XRL9akYKb
PS: I'll put the complete answer here to archive the code for future references.
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
//#see https://www.geeksforgeeks.org/multiply-large-numbers-represented-as-strings/
// Multiplies str1 and str2, and prints result.
string multiply(string num1, string num2)
{
int len1 = num1.size();
int len2 = num2.size();
if (len1 == 0 || len2 == 0)
return "0";
// will keep the result number in vector
// in reverse order
vector<int> result(len1 + len2, 0);
// Below two indexes are used to find positions
// in result.
int i_n1 = 0;
int i_n2 = 0;
// Go from right to left in num1
for (int i=len1-1; i>=0; i--)
{
int carry = 0;
int n1 = num1[i] - '0';
// To shift position to left after every
// multiplication of a digit in num2
i_n2 = 0;
// Go from right to left in num2
for (int j=len2-1; j>=0; j--)
{
// Take current digit of second number
int n2 = num2[j] - '0';
// Multiply with current digit of first number
// and add result to previously stored result
// at current position.
int sum = n1*n2 + result[i_n1 + i_n2] + carry;
// Carry for next iteration
carry = sum/10;
// Store result
result[i_n1 + i_n2] = sum % 10;
i_n2++;
}
// store carry in next cell
if (carry > 0)
result[i_n1 + i_n2] += carry;
// To shift position to left after every
// multiplication of a digit in num1.
i_n1++;
}
// ignore '0's from the right
int i = result.size() - 1;
while (i>=0 && result[i] == 0)
i--;
// If all were '0's - means either both or
// one of num1 or num2 were '0'
if (i == -1)
return "0";
// generate the result string
string s = "";
while (i >= 0)
s += std::to_string(result[i--]);
return s;
}
// Calculates the factorial of an inputed number
string fact(int in) {
string answer = "1";
for (int i = 2 ; i <= in; i++) {
string tmp = std::to_string(i);
answer = multiply(answer, tmp);
}
return answer;
}
int main()
{
string answer = fact(50);
cout << answer << endl;
return 0;
}

Armstrong numbers. print armstrong numbers

I kindly request those who think this question have been asked earlier, read on first.
I need to print all armstrong numbers between 1 and 10000. My problem is that whenever my program is run and reaches 150, it does
(1^3) + ((5^3)-1) + (0^3)
instead of
(1^3) + (5^3) + (0^3).
Thus it does not print 153 (which is an Armstrong number), of course because the sum results in 152. I do not know if some other numbers are also doing this. But i do have checked untill 200 and there is no problem with other numbers except that in 150–160 range.
Is this a compiler error. Should i re-install my compiler? Currently i am using codeblocks.
#include <iostream>
#include <math.h>
using namespace std;
int main()
{
for(int i = 0;i <= 10000;++i)
{
int r = i;
int dig = 0;
while(r != 0)
{
dig++;
r /= 10;
}
int n = i, sum = 0;
while(n != 0)
{
int d = n % 10;
sum += pow(d, dig);
n /= 10;
}
if(sum == i)
cout << i << ' ';
}
cout << "\n\n\n";
return 0;
}
You should run your code in the debugger. Also your code does not compile for me (GCC 6) because you use cout without std:: or using namespace std;. So how does it compile on your system? You are also using math.h, in C++ you should rather use cmath.
After fixing this, I get the following output on my Fedora 24 with g++ in version 6.4.1:
0 1 2 3 4 5 6 7 8 9 153 370 371 407 1634 8208 9474
The 153 is included in there, so either your compiler has an error or your program has undefined behavior and therefore the error ensues.
I have looked at the definition for Armstrong numbers and did a really short Python implementation:
# Copyright © 2017 Martin Ueding <dev#martin-ueding.de>
# Licensed under the MIT/Expat license.
def is_armstrong(number):
digits = [int(letter) for letter in str(number)]
score = sum(digit**len(digits) for digit in digits)
return score == number
armstrong = list(filter(is_armstrong, range(10000)))
print(' '.join(map(str, armstrong)))
The output matches your C++ program on my machine exactly:
0 1 2 3 4 5 6 7 8 9 153 370 371 407 1634 8208 9474
Looking through your code I cannot spot undefined behavior, it looks sensible. First you count the number of digits, then you build up the sum. Perhaps you should try with other compilers like GCC, LLVM, or Ideone. Does Code Blocks ship their own compiler or do they use a system compiler? What operating system are you running?
You said that you are just learning to program. That's cool to hear! I hope you have a good C++ book or other resource. For C++, there is a lot of bad advice on the internet. Also make sure that you have a book that has at least C++11, everything else is badly outdated.
I have changed your program and created some short functions that do just one task such that it is easier to read and reason about. I am not sure whether you already know about functions, so don't worry if that seems to complicated for now :-).
#include <cmath>
#include <iostream>
int get_digit_count(int const number) {
int digits = 0;
int remainder = number;
while (remainder > 0) {
++digits;
remainder /= 10;
}
return digits;
}
bool is_armstrong_number(int const number) {
int const digit_count = get_digit_count(number);
int remainder = number;
int sum = 0;
while (remainder > 0) {
int const last_digit = remainder % 10;
sum += std::pow(last_digit, digit_count);
remainder /= 10;
}
return number == sum;
}
int main() {
for (int i = 0; i <= 10000; ++i) {
if (is_armstrong_number(i)) {
std::cout << i << ' ';
}
}
std::cout << std::endl;
}
This algorithm generates and prints out Armstrong numbers to 999, but can easily be expanded to any length using the same methodology.
n = 1; %initialize n, the global loop counter, to 1
for i = 1 : 10 %start i loop
for j = 1 : 10 %start j loop
for k = 1 : 10 %start k loop
rightnum = mod(n, 10); %isolate rightmost digit
midnum = mod(fix((n/10)), 10); %isolate middle digit
leftnum = fix(n/100); %isolate leftmost digit
if ((n < 10)) %calulate an for single-digit n's
an = rightnum;
end
if ((n > 9) & (n < 100)) %calculate an for 2-digit n's
an = fix(rightnum^2 + midnum^2);
end
if ((n > 99) & (n < 1000)) %calculate an for 3-digit n's
an = fix(leftnum^3 + midnum^3 + rightnum^3);
end
if (n == an) %if n = an display n and an
armstrongmatrix = [n an];
disp(armstrongmatrix);
end
n = n + 1; %increment the global loop counter and continue
end
end
end
You can use arrays:
#include<iostream>
using namespace std;
int pow(int, int);
int checkArm(int);
int main() {
int range;
cout<<"Enter the limit: ";
cin>>range;
for(int i{};i<=range;i++){
if(checkArm(i))
cout<<i<<endl;
}
return 0;
}
int pow(int base, int exp){
int i{0};
int temp{base};
if(exp!=0)
for(i;i<exp-1;i++)
base = base * temp;
else
base=1;
return base;
}
int checkArm(int num) {
int ar[10], ctr{0};
int tempDigits{num};
while(tempDigits>0){
tempDigits/=10;
ctr++;
}
int tempArr{num}, tempCtr{ctr};
for(int i{0};i<=ctr;i++){
ar[i] = tempArr / pow(10,tempCtr-1);
tempArr = tempArr % pow(10,tempCtr-1);
tempCtr--;
}
int sum{};
for(int k{};k<ctr;k++){
sum+=pow(ar[k],ctr);
}
if(sum==num)
return 1;
else
return 0;
}

C++ Program abruptly ends after cin

I am writing code to get the last digit of very large fibonacci numbers such as fib(239), etc.. I am using strings to store the numbers, grabbing the individual chars from end to beginning and then converting them to int and than storing the values back into another string. I have not been able to test what I have written because my program keeps abruptly closing after the std::cin >> n; line.
Here is what I have so far.
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using namespace std;
char get_fibonacci_last_digit_naive(int n) {
cout << "in func";
if (n <= 1)
return (char)n;
string previous= "0";
string current= "1";
for (int i = 0; i < n - 1; ++i) {
//long long tmp_previous = previous;
string tmp_previous= previous;
previous = current;
//current = tmp_previous + current; // could also use previous instead of current
// for with the current length of the longest of the two strings
//iterates from the end of the string to the front
for (int j=current.length(); j>=0; --j) {
// grab consectutive positions in the strings & convert them to integers
int t;
if (tmp_previous.at(j) == '\0')
// tmp_previous is empty use 0 instead
t=0;
else
t = stoi((string&)(tmp_previous.at(j)));
int c = stoi((string&)(current.at(j)));
// add the integers together
int valueAtJ= t+c;
// store the value into the equivalent position in current
current.at(j) = (char)(valueAtJ);
}
cout << current << ":current value";
}
return current[current.length()-1];
}
int main() {
int n;
std::cin >> n;
//char& c = get_fibonacci_last_digit_naive(n); // reference to a local variable returned WARNING
// http://stackoverflow.com/questions/4643713/c-returning-reference-to-local-variable
cout << "before call";
char c = get_fibonacci_last_digit_naive(n);
std::cout << c << '\n';
return 0;
}
The output is consistently the same. No matter what I enter for n, the output is always the same. This is the line I used to run the code and its output.
$ g++ -pipe -O2 -std=c++14 fibonacci_last_digit.cpp -lm
$ ./a.exe
10
There is a newline after the 10 and the 10 is what I input for n.
I appreciate any help. And happy holidays!
I'm posting this because your understanding of the problem seems to be taking a backseat to the choice of solution you're attempting to deploy. This is an example of an XY Problem, a problem where the choice of solution method and problems or roadblocks with its implementation obfuscates the actual problem you're trying to solve.
You are trying to calculate the final digit of the Nth Fibonacci number, where N could be gregarious. The basic understanding of the fibonacci sequence tells you that
fib(0) = 0
fib(1) = 1
fib(n) = fib(n-1) + fib(n-2), for all n larger than 1.
The iterative solution to solving fib(N) for its value would be:
unsigned fib(unsigned n)
{
if (n <= 1)
return n;
unsigned previous = 0;
unsigned current = 1;
for (int i=1; i<n; ++i)
{
unsigned value = previous + current;
previous = current;
current = value;
}
return current;
}
which is all well and good, but will obviously overflow once N causes an overflow of the storage capabilities of our chosen data type (in the above case, unsigned on most 32bit platforms will overflow after a mere 47 iterations).
But we don't need the actual fib values for each iteration. We only need the last digit of each iteration. Well, the base-10 last-digit is easy enough to get from any unsigned value. For our example, simply replace this:
current = value;
with this:
current = value % 10;
giving us a near-identical algorithm, but one that only "remembers" the last digit on each iteration:
unsigned fib_last_digit(unsigned n)
{
if (n <= 1)
return n;
unsigned previous = 0;
unsigned current = 1;
for (int i=1; i<n; ++i)
{
unsigned value = previous + current;
previous = current;
current = value % 10; // HERE
}
return current;
}
Now current always holds the single last digit of the prior sum, whether that prior sum exceeded 10 or not really isn't relevant to us. Once we have that the next iteration can use it to calculate the sum of two single positive digits, which cannot exceed 18, and again, we only need the last digit from that for the next iteration, etc.. This continues until we iterate however many times requested, and when finished, the final answer will present itself.
Validation
We know the first 20 or so fibonacci numbers look like this, run through fib:
0:0
1:1
2:1
3:2
4:3
5:5
6:8
7:13
8:21
9:34
10:55
11:89
12:144
13:233
14:377
15:610
16:987
17:1597
18:2584
19:4181
20:6765
Here's what we get when we run the algorithm through fib_last_digit instead:
0:0
1:1
2:1
3:2
4:3
5:5
6:8
7:3
8:1
9:4
10:5
11:9
12:4
13:3
14:7
15:0
16:7
17:7
18:4
19:1
20:5
That should give you a budding sense of confidence this is likely the algorithm you seek, and you can forego the string manipulations entirely.
Running this code on a Mac I get:
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: basic_string before callin funcAbort trap: 6
The most obvious problem with the code itself is in the following line:
for (int j=current.length(); j>=0; --j) {
Reasons:
If you are doing things like current.at(j), this will crash immediately. For example, the string "blah" has length 4, but there is no character at position 4.
The length of tmp_previous may be different from current. Calling tmp_previous.at(j) will crash when you go from 8 to 13 for example.
Additionally, as others have pointed out, if the the only thing you're interested in is the last digit, you do not need to go through the trouble of looping through every digit of every number. The trick here is to only remember the last digit of previous and current, so large numbers are never a problem and you don't have to do things like stoi.
As an alternative to a previous answer would be the string addition.
I tested it with the fibonacci number of 100000 and it works fine in just a few seconds. Working only with the last digit solves your problem for even larger numbers for sure. for all of you requiring the fibonacci number as well, here an algorithm:
std::string str_add(std::string a, std::string b)
{
// http://ideone.com/o7wLTt
size_t n = max(a.size(), b.size());
if (n > a.size()) {
a = string(n-a.size(), '0') + a;
}
if (n > b.size()) {
b = string(n-b.size(), '0') + b;
}
string result(n + 1, '0');
char carry = 0;
std::transform(a.rbegin(), a.rend(), b.rbegin(), result.rbegin(), [&carry](char x, char y)
{
char z = (x - '0') + (y - '0') + carry;
if (z > 9) {
carry = 1;
z -= 10;
} else {
carry = 0;
}
return z + '0';
});
result[0] = carry + '0';
n = result.find_first_not_of("0");
if (n != string::npos) {
result = result.substr(n);
}
return result;
}
std::string str_fib(size_t i)
{
std::string n1 = "0";
std::string n2 = "1";
for (size_t idx = 0; idx < i; ++idx) {
const std::string f = str_add(n1, n2);
n1 = n2;
n2 = f;
}
return n1;
}
int main() {
const size_t i = 100000;
const std::string f = str_fib(i);
if (!f.empty()) {
std::cout << "fibonacci of " << i << " = " << f << " | last digit: " << f[f.size() - 1] << std::endl;
}
std::cin.sync(); std::cin.get();
return 0;
}
Try it with first calculating the fibonacci number and then converting the int to a std::string using std::to_string(). in the following you can extract the last digit using the [] operator on the last index.
int fib(int i)
{
int number = 1;
if (i > 2) {
number = fib(i - 1) + fib(i - 2);
}
return number;
}
int main() {
const int i = 10;
const int f = fib(i);
const std::string s = std::to_string(f);
if (!s.empty()) {
std::cout << "fibonacci of " << i << " = " << f << " | last digit: " << s[s.size() - 1] << std::endl;
}
std::cin.sync(); std::cin.get();
return 0;
}
Avoid duplicates of the using keyword using.
Also consider switching from int to long or long long when your numbers get bigger. Since the fibonacci numbers are positive, also use unsigned.