Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I'm trying to find maximum the Collatz sequence between 1 and 1000000. I wrote the following code below. I guess it is correct but it is extremely slow. Can you give me a few hints to make it faster? Thanks.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool myfn(int i, int j) { return i<j; }
int collatz(int x);
int main()
{
vector <int> myvector;
for(int i = 1; i < 1000000; i++)
{
myvector.push_back(collatz(i));
}
cout<<*max_element(myvector.begin(),myvector.end(),myfn);
return 0;
}
int collatz(int x)
{
int counter = 1;
while(1)
{
if(x == 1)
break;
if(x % 2 == 0)
{
x = x / 2;
counter++;
}
else
{
x = 3 * x + 1;
counter++;
}
}
return counter;
}
Actually, I just tested, and your code isn't just "extremely slow", but infinitely looping. No, you didn't just disprove the Collatz conjecture, but as far as I can see, you're suffering from an integer overflow.
More specifically, during the collatz(113383) the int x variable becomes negative due to an overflow:
551580299 1654740898 827370449 -1812855948 -906427974 -453213987
Shortly after that, it starts looping on the following sequence and thus consequently never exits the loop
-37 -110 -55 -164 -82 -41 -122 -61 -182 -91 -272 -136 -68 -34 -17 -50 -25 -74 -37 ...
After I changed the int x argument to a long long, the program quite quickly finishes.
The question then of course still is whether no overflows occur that don't cause infinite loops and go unnoticed, as you would then still end up with the wrong answer. However, after putting
if (x < 0) {
cout << "ERROR" << endl;
}
at the end of the while(1) loop and seeing nothing being output extra, I think you can be confident that a long long is big enough for the Collatz sequences for the numbers 1 to 1000000 (8 bytes, on my computer, compared to 4 bytes for an int, if you'd be interested).
EDIT:
As a side note: I don't see any reason to keep a vector of all results if you only need the maximum. Following code would eat less memory:
int maxCollatz = 0;
for(int i = 1; i < 1000000; i++) {
if (i % 10000 == 0)
cout << i << endl;
maxCollatz = max(maxCollatz, collatz(i));
}
And another note: you're actually only looping from 1 to 999999, so if the Collatz sequence for 1000000 would be the longest one, you might be missing that one...
Here are some tips:
Initialize vector to your capacity.
The vector may be expanding while you are pushing elements. Worst case, one reallocation per push_back.
Treat vector as array
After you have initialized your vector to its capacity, you can use the operator [] to access the vector slot instead of calling push_back.
Optimize collatz
This is probably your bottleneck. Try placing into a separate file and cranking up the compiler optimizations on it.
There may be a more optimal algorithm.
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 days ago.
Improve this question
I'm coding for the Strong number problem and when I run it, i passed 3 cases. But when I run 4th case nothing happens.
I passed: 1, 2, 145 but 40585.
Here is my code:
#include <iostream>
using namespace std;
int Get(int n);
int Factorial(int n, int sum);
int main()
{
system("cls");
int n;
cout << "Enter. \n";
cin >> n;
if (n == Get(n))
{
cout << "True. \n";
}
else
{
cout << "False. \n";
}
return 0;
}
int Get(int n)
{
static int sum = 0;
if (n / 10)
{
Get (n / 10);
}
return sum += Factorial(n % 10, 1);
}
int Factorial(int n, int sum)
{
if (n == 1)
{
return sum;
}
else
{
return Factorial(n - 1, sum *= n);
}
}
I don't know why, so pls help me !
The problem is that in this line:
return sum += Factorial(n % 10, 1);
You call Factorial with n % 10 which can be 0.
This is not handled well by Factorial (it will recurse infinitely with negative values for n).
You can fix it by changing the recursion stop condition in Factorial to:
if (n <= 1)
{
// ...
}
A side note:
If you can implement a function using iteration (i.e. loops) instead of recursion - this is usually recommended. This is because recursion uses the stack which is usually relatively small.
For calculating factorial you have to cope with an additional issue of int overflowing very fast - 13! is already too big to be stored in a 32 bit integer. You can handle it by e.g. using a 64 bit integer or some big number library for bigger values.
However - in this specific case since the Factorial is calculated for a max value of 9 both issues are OK (although I would still prefer using one simple loop for factorial).
As #lastchance commented, you can also keep all the required 10 values (for 0! .. 9!) in a precalculated array.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Problem:
Petya loves lucky numbers. We all know that lucky numbers are the positive integers whose decimal representations contain only the lucky digits 4 and 7. For example, numbers 47, 744, 4 are lucky and 5, 17, 467 are not.
Unfortunately, not all numbers are lucky. Petya calls a number nearly lucky if the number of lucky digits in it is a lucky number. He wonders whether number n is a nearly lucky number.
Input
The only line contains an integer n (1 ≤ n ≤ 1018).
Output
Print on the single line "YES" if n is a nearly lucky number. Otherwise, print "NO" (without the quotes).
I submitted a solution on this problem and fail at the input of 4744000695826. This should give an output of YES, since it has 4 lucky numbers, and 4 is a lucky number itself. However I get an output of NO. This was the first input test which contained 4s and 7s and was bigger than 32 bit int limit 232-1, so I guess that has something to do with it, but I honestly don't know.
Here is my code:
#include <iostream>
#include <cmath>
#include <bits/stdc++.h>
#include <cstring>
using namespace std;
// counting digits in an int
int count_digit(int number) {
return int(log10(number) + 1);
}
// counting certain digits in an int
int counter(int b, int n) {
int count = 0;
while(b > 0) {
if(b % 10 == n) {
count++;
}
b /= 10;
}
return count;
}
int main()
{
int k;
cin >> k;
int r = counter(k,4) + counter(k,7);
if (count_digit(r) - (counter(r,4) + counter(r,7)) == 0) {
cout << "YES";
}
else {
cout << "NO";
}
return 0;
}
If you want to process numbers greater than your ints, you need to use something else.
For example, you could:
std::string number;
std::cin >> number;
Then you can check the number with
char value = '5';
for(const char& c: number)
{
if (c == value);
}
That way you're not even limited to 64 bits.
Even more modern/idiomatic would be to use std::count:
https://en.cppreference.com/w/cpp/algorithm/count
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
You are given a number, at a time either you can increase a number by 1 or decrease by 1 it is considered as one move find the minimum number of moves required to convert a given into a lucky number. A number is called lucky if all the digits in it are even.
I have writtern the code but I am not sure if it is correct. Can anybody please confirm me?
#include<bits/stdc++.h>
using namespace std;
int count(int n)
{
int count = 0;
while (n != 0)
{
n = n / 10;
++count;
}
return count;
}
int firstDigit(int n)
{
// Remove last digit from number
// till only one digit is left
while (n >= 10)
n /= 10;
// return the first digit
return n;
}
int main()
{
int n;
cin >> n;
int i,j,ans=0;
int x = count(n);
while(x--)
{
if(firstDigit(n)%2 != 0)
{
if(firstDigit(n) == 9)
{
ans = ans + pow(10,x);
n = n-pow(10,x);
}
else
{
ans = ans + pow(10,x);
n = n + pow(10,x);
}
}
else
n = n - pow(10,x);
}
cout << ans << endl;
}
Edit:
I found it is giving wrong answer at 100. Can you please help me in finding out the mistake
Not all code can easily be tested, thats why you should strive to write testable code right from the start (instead of first writing it all and then try to confirm correctness). In your case testability could benefit a lot from moving most logic from main into a dedicated function:
int minimal_steps(int input) {
....
}
Once you have that, you can either call it in main with user supplied input just as you do it now, but you can also write tests more easily:
void test() {
assert( minimal_steps(2222) == 0);
assert( minimal_steps(2221) == 1);
...etc...
}
Once you got into the habit of testing your code (you should also write tests for count and firstDigit) you may consider to use a testing framework to automate tests.
PS: It isnt wrong, but it is such a waste of CPU cycles that it is worth mentioning (actually it was already mentioned in a comment). You do not need to compute pow(10,x) in a loop where x is the loop counter. Consider that you are computing 10^2 almost as many times as the loop has iterations. Also 10^3 is the same in every iteration. Instead you should only update with *10 (in case x is incremented) or /10 when x decrements between iterations. Moreover, pow is for floating-points, not for integers.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
#include <iostream>
using namespace std;
int checkIfPrime(int num) {
for (int i = 1; i < num; i++) {
int result = num / i;
if (num == result * i) {
return 0;
}
}
}
int main() {
int i = 3;
while(1) {
int c = checkIfPrime(i);
if (c != 0) {
cout << c << "\n";
}
i = i + 2;
}
}
Sorry about posting the wrong code!
When I run this, nothing happens.. Can someone tell me what I am doing wrong?
After the question has completely changed its meaning:
Your CheckIfPrime is just wrong. You're checking divisibility in a very strange way. The general way to check whether a is divisible by b is if(a % b == 0)
That said, your error is that your loop starts with 1. Of course every number is divisible by 1, therefore by your logic, no number is prime. Start with for(int i = 2; .... (Depending on whether you want to consider 1 as prime or not, you might want to test specially for num == 1 initially.)
Also, the end condition is very inefficient. It is enough to check before the square root of num, that is i <= sqrt(num), but since sqrt is a rather slow and imprecise operation, MUCH better is to loop this way:
for(int i = 2; i * i < = num; ++i)
Another note - to generate all prime numbers from 1 to some MAX_VAL, your approach is very inefficient. Use the Sieve of Erastothenes.
Some stylistic note: your function should ideally return bool rather than int, and don't forget to return true or 1 after the loop has finished without returning.
Original Answer:
First of all, you need
fprintf(OUTPUT_FILE, "%d", Num); //d instead of s, no & before Num
instead of
fprintf(OUTPUT_FILE, "%s", &Num);
Second, you use the file I/O extremely inefficiently. Why do you open and close the file for every number? You should open it once, write all numbers, and then close it.
And thirdly, your algorithm doesn't seem to have anything to do with prime numbers... :)
By the way, since the first issue results in Undefined Behavior, you can't complain about any behavior of the program, since it's... well, undefined.
You aren't error checking any of your FileIO - wonder if something's going wrong there. A few ifs could help sort that out. Beyond that, all I see is an app that will fill your HDD real fast if it's working correctly.
The main reason why your prime generator isn't working, that i can see:
for (int i = 1; i < num; i++) {
int result = num / i;
if (num == result * i) {
return 0;
}
}
You start checking at 1. Since every number / 1 == itself, and every number * 1 == itself, the condition will always be true on the first run; that is, your prime test will always return false. Start at 2 instead.
Once you fix that, you should also make it so that the test returns true if it manages to get all the way through the loop. (Inserting a return 1; after the loop should be enough.)
(BTW, if you care the least bit about efficiency, if ((num & 1) == 0) return 0; for (int i = 3; i * i <= num; i += 2) would be better. But better still would be a sieve of some sort, as mentioned elsewhere.)
int checkIfPrime(int num) {
for (int i = 1; i < num; i++) {
int result = num / i;
if (num == result * i) {
return 0;
}
}
}
Missing return 1 at the end of the loop
The initial value of i must not be 1. Walk through the first iteration with a pencil and paper and see what happens.
I'm working on Euler Problem 14:
http://projecteuler.net/index.php?section=problems&id=14
I figured the best way would be to create a vector of numbers that kept track of how big the series was for that number... for example from 5 there are 6 steps to 1, so if ever reach the number 5 in a series, I know I have 6 steps to go and I have no need to calculate those steps. With this idea I coded up the following:
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
int main()
{
vector<int> sizes(1);
sizes.push_back(1);
sizes.push_back(2);
int series, largest = 0, j;
for (int i = 3; i <= 1000000; i++)
{
series = 0;
j = i;
while (j > (sizes.size()-1))
{
if (j%2)
{
j=(3*j+1)/2;
series+=2;
}
else
{
j=j/2;
series++;
}
}
series+=sizes[j];
sizes.push_back(series);
if (series>largest)
largest=series;
cout << setw(7) << right << i << "::" << setw(5) << right << series << endl;
}
cout << largest << endl;
return 0;
}
It seems to work relatively well for smaller numbers but this specific program stalls at the number 113382. Can anyone explain to me how I would go about figuring out why it freezes at this number?
Is there some way I could modify my algorithim to be better? I realize that I am creating duplicates with the current way I'm doing it:
for example, the series of 3 is 3,10,5,16,8,4,2,1. So I already figured out the sizes for 10,5,16,8,4,2,1 but I will duplicate those solutions later.
Thanks for your help!
Have you ruled out integer overflow? Can you guarantee that the result of (3*j+1)/2 will always fit into an int?
Does the result change if you switch to a larger data type?
EDIT: The last forum post at http://forums.sun.com/thread.jspa?threadID=5427293 seems to confirm this. I found this by googling for 113382 3n+1.
I think you are severely overcomplicating things. Why are you even using vectors for this?
Your problem, I think, is overflow. Use unsigned ints everywhere.
Here's a working code that's much simpler and that works (it doesn't work with signed ints however).
int main()
{
unsigned int maxTerms = 0;
unsigned int longest = 0;
for (unsigned int i = 3; i <= 1000000; ++i)
{
unsigned int tempTerms = 1;
unsigned int j = i;
while (j != 1)
{
++tempTerms;
if (tempTerms > maxTerms)
{
maxTerms = tempTerms;
longest = i;
}
if (j % 2 == 0)
{
j /= 2;
}
else
{
j = 3*j + 1;
}
}
}
printf("%d %d\n", maxTerms, longest);
return 0;
}
Optimize from there if you really want to.
When i = 113383, your j overflows and becomes negative (thus never exiting the "while" loop).
I had to use "unsigned long int" for this problem.
The problem is overflow. Just because the sequence starts below 1 million does not mean that it cannot go above 1 million later. In this particular case, it overflows and goes negative resulting in your code going into an infinite loop. I changed your code to use "long long" and this makes it work.
But how did I find this out? I compiled your code and then ran it in a debugger. I paused the program execution while it was in the loop and inspected the variables. There I found that j was negative. That pretty much told me all I needed to know. To be sure, I added a cout << j; as well as an assert(j > 0) and confirmed that j was overflowing.
I would try using a large array rather than a vector, then you will be able to avoid those duplicates you mention as for every number you calculate you can check if it's in the array, and if not, add it. It's probably actually more memory efficient that way too. Also, you might want to try using unsigned long as it's not clear at first glance how large these numbers will get.
i stored the length of the chain for every number in an array.. and during brute force whenever i got a number less than that being evaluated for, i just added the chain length for that lower number and broke out of the loop.
For example, i already know the Collatz sequence for 10 is 7 lengths long.
now when i'm evaluating for 13, i get 40, then 20, then 10.. which i have already evaluated. so the total count is 3 + 7.
the result on my machine (for upto 1 million) was 0.2 secs. with pure brute force that was 5 seconds.