Segmentation Fault C++ (array too large?) - c++

I'm working on the Project Euler Problem 14, where I need to find the longest collatz sequence under 1,000,000. I've come up with an algorithm that works for smaller numbers (say, 100) that stores each collatz number from 1 - 100 into an array and uses that array as a reference to speed up the computations for higher numbers.
My code is as follows:
#include <iostream>
using namespace std;
long even(long n){ //the even-collatz function
n=n/2;
return n;
}
long odd(long n){ //the odd collatz function
n=3*n+1;
return n;
}
int main(){
long x, c=0, y[1000000]; // x= the number we are finding the collatz number of, c a counter that keeps track of how many steps we've taken in the sequence, y is an array to store the collatz numbers.
for (x=1; x<1000000; x++){ //iterates from x=1 to 1 million
long a = x; //sets a number a equal to the number we are currently trying to find the collatz number of
long b = a;
c=0; //intializes counter at 0
while (a!=0){ //loops infinitely; the only way to exit is through a break.
if (a%2==0){ // detects if the number is even
a=even(a); //applies the even-collatz function if so; sets x=x/2
c=c+1;
if (y[a]!=0){ // checks if the collatz number of x is already discovered
y[b]=c+y[a]; //adds the current number of steps to the collatz number of x and
break; //exits the while loop
}
}
else if (a==1){ //checks if the new x is equal to one and
y[b]=c; //if it is, it writes the current value of c to y[b] and
break; // exits the loop
}
else if (a%2==1){ //same as the "even" block, except for odd numbers
a=odd(a);
c=c+1;
if( y[a]!=0){
y[b]=c+y[a];
break;
}
}
//this is the end of the while loop; we've applied the collatz function as many times as we've needed to to x, and incremented the counter each time
}
}
long z;
for (int n=0;n!=100;n++){
if (y[n+1]>y[n]){
z=y[n+1];
}
}
cout << z << "\n";
}
The issue I'm having is that I get a segfault after x=1818 in the for loop. Through debugging, I've found that how quickly the segfault occurs depends on the size of array y, so I'm assuming that the array is just too big. From my (basic) understanding of segfaults, I think I'm just accessing memory that I'm "not allowed". Is there any way for me to circumvent this, or should I just start working towards another solution to this problem? I'm compiling using g++ on Ubuntu studio.

This array is probably too big for your system's default stack size; the simplest fix is to change its definition to:
std::vector<long> y(1000000);
and everything else can stay the same. You could use y.size() instead of the magic number 1000000 later in your loop.

For a starting number under N collatz sequence can go way beyond N. For N == 1000000 consider x == 333335.
I would suggest you to make y a vector<int> and expand it dynamically, or just make it unordered_map<int, int>.

If y was too big for your stack, you would get a stack overflow exception as soon as main tried to run.
Your problem is more likely that a gets bigger than the size of y.
When I ran it through the debugger, a was 1417174 when x was 4255, so you might have a problem with your algorithm.
That said, you should either allocate it yourself, or make it static, as there is no guarantee that whatever compiler Project Euler uses will allow such a large stack size.

Related

1838. Frequency of the Most Frequent Element leetcode C++

I am trying LeetCode problem 1838. Frequency of the Most Frequent Element:
The frequency of an element is the number of times it occurs in an array.
You are given an integer array nums and an integer k. In one operation, you can choose an index of nums and increment the element at that index by 1.
Return the maximum possible frequency of an element after performing at most k operations.
I am getting a Wrong Answer error for a specific test case.
My code
int checkfreq(vector<int>nums,int k,int i)
{
//int sz=nums.size();
int counter=0;
//int i=sz-1;
int el=nums[i];
while(k!=0 && i>0)
{
--i;
while(nums[i]!=el && k>0 && i>=0)
{
++nums[i];
--k;
}
}
counter=count(nums.begin(),nums.end(),el);
return counter;
}
class Solution {
public:
int maxFrequency(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());
vector<int> nums2=nums;
auto distinct=unique(nums2.begin(),nums2.end());
nums2.resize(distance(nums2.begin(),distinct));
int xx=nums.size()-1;
int counter=checkfreq(nums,k,xx);
for(int i=nums2.size()-2;i>=0;--i)
{
--xx;
int temp=checkfreq(nums,k,xx);
if(temp>counter)
counter=temp;
}
return counter;
}
};
Failing test case
Input
nums = [9968,9934,9996,9928,9934,9906,9971,9980,9931,9970,9928,9973,9930,9992,9930,9920,9927,9951,9939,9915,9963,9955,9955,9955,9933,9926,9987,9912,9942,9961,9988,9966,9906,9992,9938,9941,9987,9917,10000,9919,9945,9953,9994,9913,9983,9967,9996,9962,9982,9946,9924,9982,9910,9930,9990,9903,9987,9977,9927,9922,9970,9978,9925,9950,9988,9980,9991,9997,9920,9910,9957,9938,9928,9944,9995,9905,9937,9946,9953,9909,9979,9961,9986,9979,9996,9912,9906,9968,9926,10000,9922,9943,9982,9917,9920,9952,9908,10000,9914,9979,9932,9918,9996,9923,9929,9997,9901,9955,9976,9959,9995,9948,9994,9996,9939,9977,9977,9901,9939,9953,9902,9926,9993,9926,9906,9914,9911,9901,9912,9990,9922,9911,9907,9901,9998,9941,9950,9985,9935,9928,9909,9929,9963,9997,9977,9997,9938,9933,9925,9907,9976,9921,9957,9931,9925,9979,9935,9990,9910,9938,9947,9969,9989,9976,9900,9910,9967,9951,9984,9979,9916,9978,9961,9986,9945,9976,9980,9921,9975,9999,9922]
k = 1524
Output
Expected: 81
My code returns: 79
I tried to solve as many cases as I could. I realise this is a bruteforce approach, but don't understand why my code is giving the wrong answer.
My approach is to convert numbers from last into the specified number. I need to check these as we have to count how many maximum numbers we can convert. Then this is repeated for every number till second last number. This is basically what I was thinking while writing this code.
The reason for the different output is that your xx index is only decreased one unit at each iteration of the i loop. But that loop is iterating for the number of unique elements, while xx is an index in the original vector. When there are many duplicates, that means xx is coming nowhere near the start of the vector and so it misses opportunities there.
You could fix that problem by replacing:
--xx;
...with:
--xx;
while (xx >= 0 && nums[xx] == nums[xx+1]) --xx;
if (xx < 0) break;
That will solve the issue you raise. You can also drop the unique call, and the distinct, nums2 and i variables. The outer loop could just check that xx > 0.
Efficiency is your next problem
Your algorithm is not as efficient as needed, and other tests with huge input data will time out.
Hint 1: checkfreq's inner loop is incrementing nums[i] one unit at a time. Do you see a way to have it increase with a larger amount, so to avoid that inner loop?
Hint 2 (harder): checkfreq is often incrementing the same value in different calls -- even more so when k is large and the section of the vector that can be incremented is large. Can you think of a way to avoid that checkfreq needs to redo that much work in subsequent calls, and can only concentrate on what is different compared to what it had to calculate in the previous call?

sieve or eratosthenes calculator -- running into memory issues and crashing with numbers >=1,000,000

I'm not exactly sure why this is. I tried changing the variables to long long, and I even tried doing a few other things -- but its either about the inefficiency of my code (it literally does the whole process of finding all primes up to the number, then checking against the number to see if its divisible by that prime -- very inefficient, but its my first attempt at this and I feel pretty accomplished having it work at all....)
Or the fact that it overflows the stack. Im not sure where it is exactly, but all I know is that it MUST be related to memory and the way its dealing with the number.
If I had to guess, Id say its a memory issue happening when it is dealing with the prime number generation up to that number -- thats where it dies even if I remove the check against the input number.
I'll post my code -- just be aware, I didnt change long long back to int in a few places, and I also have a SquareRoot Variable that is not used, because it was supposed to try and help memory efficiency but was not effective the way I tried to do it. I Just never deleted it. I will clean up the code when and if I can successfully finish it.
As far as I am aware though, it DOES work pretty reliably for 999,999 and down, I actually checked it up against other calculators of the same type and it seemingly does generate the proper answers.
If anyone can help or explain what I screwed up here, your helping a guy trying to learn on his own without any school or anything. so its appreciated.
#include <iostream>
#include <cmath>
void sieve(int ubound, int primes[]);
int main()
{
long long n;
int i;
std::cout << "Input Number: ";
std::cin >> n;
if (n < 2) {
return 1;
}
long long upperbound = n;
int A[upperbound];
int SquareRoot = sqrt(upperbound);
sieve(upperbound, A);
for (i = 0; i < upperbound; i++) {
if (A[i] == 1 && upperbound % i == 0) {
std::cout << " " << i << " ";
}
}
return 0;
}
void sieve(int ubound, int primes[])
{
long long i, j, m;
for (i = 0; i < ubound; i++) {
primes[i] = 1;
}
primes[0] = 0, primes[1] = 0;
for (i = 2; i < ubound; i++) {
for(j = i * i; j < ubound; j += i) {
primes[j] = 0;
}
}
}
If you used legal C++ constructs instead of non-standard variable length arrays, your code will run (whether it produces the correct answers is another question).
The issue is more than likely that you're exceeding the limits of the stack when you declare arrays with a million or more elements.
Therefore instead of this:
long long upperbound = n;
A[upperbound];
Use std::vector:
#include <vector>
//...
long long upperbound = n;
std::vector<int> A(upperbound);
and then:
sieve(upperbound, A.data());
The std::vector does not use the stack space to allocate its elements (unless you have written an allocator for it that uses the stack).
As a matter of fact, you don't even need to pass upperbound to sieve, as a std::vector knows its own size by calling the size() member function. But I leave that as an exercise.
Live example using 2,000,000
First of all, read and apply PaulMcKenzie's advice. That's the most important thing. I'm only addressing some teeny bits of your question that remained open.
It seems that you are trying to factor the number that you misleadingly called upperbound. The mysterious role of the square root of this number is related to this fact: if the number is composite at all - and hence can be computed as the product of some prime factors - then the smallest of these prime factors cannot be greater than the square root of the number. In fact, only one factor can possibly be greater, all others cannot exceed the square root.
However, in its present form your code cannot draw advantage from this fact. The trial division loop as it stands now has to run up to number_to_be_factored / 2 in order not to miss any factors because its body looks like this:
if (sieve[i] == 1 && number_to_be_factored % i == 0) {
std::cout << " " << i << " ";
}
You can factor much more efficiently if you refactor your code a bit: when you have found the smallest prime factor p of your number then the remaining factors to be found must be precisely those of rest = number_to_be_factored / p (or n = n / p, if you will), and none of the remaining factors can be smaller than p. However, don't forget that p might occur more than once as a factor.
During any round of the proceedings you only need to consider the prime factors between p and the square root of the current number; if none of those primes divides the current number then it must be prime. To test whether p exceeds the square root of some number n you can use if (p * p > n), which is computationally more efficient that actually computing the square root.
Hence the square root occurs in two different roles:
the square root of the number to be factored limits the amount of sieving that needs to be done
during the trial division loop, the square root of the current number gives an upper bound for the highest prime factor that you need to consider
That's two faces of the same coin but two different usages in the actual code.
Note: once you got your code working by applying PaulMcKenzie's advice, you might also to consider posting over on Code Review.

Prime number (SIGSEGV)

This is a very famous problem on SPOJ where you need to find prime numbers in a given range so the thing is the range lies from 1 to 1000000000.But every time i allocate an array of 1000000000 size it will give me a sigsegv error or a sigabrt error how do i overcome this problem of assigning very large values to an array
Apart from that i am using the sieve of ertosthenes algorithm to solve the problem.I have given the code below please help me resolve the problem by telling me what i need to change in my code so i don't get a sigsegv and sigabrt error.
#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
int t,j;
long long int x,y;
cin>>t;
int i=0;
while(i<t)
{
cin>>x>>y;
long long int *a=new long long int[y];
for(int k=0;k<=y;k++)
a[k]=1;
a[0]=0;
a[1]=0;
for(int k=2;k<=y;k++)
{
if(a[k]==1)
{
for(j=2;k*j<=y;j++)
a[k*j]=0;
}
}
for(int k=x;k<=y;k++)
{
if(a[k]==1)
cout<<k;
}
delete []a;
i++;
}
return 0;
}
please help me resolve the problem by telling me what i need to change in my code so i don't get a sigsegv and sigabrt error.
Change:
long long int *a=new long long int[y];
to:
std::vector<bool> a=std::vector<bool>(y);
std::vector<bool> will allocate 1 bit for each 0/1 value, instead of the 64 bits that you are probably allocating for each.
It looks like you're using something similar to the Sieve of Eratosthenes. The algorithm looks like:
bool composite[N] := {false, ..., false}
composite[0] := true
composite[1] := true
for (i from 2 to N)
if (not composite[i])
for (j = 2i to N skipping by i)
composite[j] := true
For ranges like [1, 10^9], a nice option to cut memory usage is to use bit masking instead of booleans. This way, you use ~128MB instead of ~1GB of memory for the sieve. Edit: I forgot to mention that std::vector<bool> is actually internally a std::bitset, so you don't actually have to do any explicit bit twiddling.
A better option in terms of memory is to use the fact that a number is composite iff it has a non-trivial factor less than or equal to its square root, and combine that with a sieve. Of course, you have to augment the sieve with a list of primes. It will be empty initially, and you must append a prime each time you find one.
Sieve all of the primes up to 32,000 (A little more than the square root of 1,000,000,000). The result is a sorted sequence of prime numbers.
For each integer k, iterate over the primes less than or equal to the square root of k. If it's divisible by one of them, it's not prime. Otherwise, if the loop terminates, it's prime. When k < 32,000, you can avoid this entirely and just use the flag set in the sieve array.
This gives you O(sqrt(N) log log sqrt(N)) complexity for the sieve, and checking if an integer k is prime takes time O(sqrt(k) / log sqrt(k)) by the Prime Number Theorem.

Problems with program which find prime number from 1 to 100

I wrote this program which find and displays prime numbers from 1 to 100
int ifprime (int n)
{
int i=1;
while (i<= n)
{
i++;
if (n%i == 0)
{
return false;
break;
}
else continue;
}
return true;
}
int prime_numbers (void)
{
bool result;
for (int i = 2; i<=100; ++i)
{
result = ifprime(i);
if (result==true) cout<<i<<endl;
else continue;
}
}
int main()
{
prime_numbers();
return 0;
}
The program displays nothing. Why?
Change your loop to:
for(int i=2; i<n; i++){
if(n%i==0){
return false;
}
}
Or your while end condition to:
while(i < n-1)
As pointed out in the comments, every non-zero number is divisible by 1 and itself. Change this line (line 4)
while (i<= n)
to
while (i< n)
If that's your whole code, then you're simply missing a main() function.
Though it shouldn't link without a main() function.
There are some additional problems with your code, but that's probably the reason why you don't see any output.
Try adding this to your file:
int main()
{
prime_numbers();
return 0;
}
Many people have pointed out the problem with:
while (i <= n)
...because you allow i to be n in your for loop, every natural number is divisible by itself so it wrongly accuses prime numbers of being composites. As people pointed out, the quick fix is:
while (i < n)
But the reason why I reply is because there are other things you can do to make your code better. The first improvement is that you don't need to try dividing by numbers greater than the square root of n because if there is a greater than it, then there is also a divisor less than it. So you could do something like this:
while (i*i <= n)
But there are further improvements you can do on that. For example, why should you have to compute i*i every iteration? If you pre-compute square root of n (rounded to int), then you can avoid that computation.
Another optimization is that you can avoid trial dividing by half of the numbers: if n is not divisible by 2, then no reason to try any other even numbers. So you can jump i by 2 every time in your inner loop. There are other tricks if you want to eliminate trial dividing by numbers divisible by 3.
Really, however, there is a nice super-duper fast algorithm to find the first x primes if you don't mind using order x bytes of memory. It is called the sieve of Eratosthenes, and it is really fun to implement. Once you get your current code optimized, I recommend trying the sieve.
The problem of finding prime numbers efficiently has received an enormous amount of attention in the academic literature, and it is now considered solved. But it takes a lot of study to learn it.

C++ Program hangs when calling a function

I have written a code which checks whether a integer is prime or not,whenever i am calling that function the command line just hangs.
I am using MingW in Windows 7
#include<iostream>
#include<math.h>
using namespace std;
bool checkPrime(int n);
int main()
{
int t,tempstart;
cout<<checkPrime(6);
return 0;
}
bool checkPrime(int n)
{
bool check=true;
for (int i = 0; i <(int) sqrt(n) ; i++)
{
if(n%i==0)
{
check=false;
cout<<"asas";
break;
}
}
return check;
}
it should not hang-up at least not for n=6
1.try this
instead of:
if(n%i==0)
write:
if((n%i)==0)
some compilers do a mess with multi operation conditions so bracketing usually helps
2.as mentioned i should go from 2
n%0 is division by zero maybe your code thrown hidden exception and that is what is wrong
3.have you try to debug it ?
get a breakpoint inside for loop and step it and see why it is not stopping when i==2,3
Tips for speeding it up a little (just few thousand times for bigger n)
1.i=2,3,5,7,9,11,13,...
as mentioned in comments do i=2 separately (by (n&1)==0 instead of (n%2)==0)
and the rest:
for (nn=sqrt(n),i=3;i<=nn;i+=2) ...
2.instead of sqrt(n) use number with the half of bits
3.do not compute sqrt inside for (some compilers do not pre-compute)
4.use sieve of Aristoteles
create one or more arrays which will eliminate few divisions from you
do not forget to use array size as common multiply of dividers inside it
this is what can speed up things considerably
because it can eliminate many for cycles with a single array access
but it need initialization of arrays prior to their use
for example array
BYTE sieve[4106301>>1]; //only odd numbers are important so the size is half and each bit hold one sieve value so the size is really 4106301*8 which is divided by:
can hold sieves for dividers:
3,5,7,11,13,17,19,23,137,131,127,113,83,61,107,101,
103,67,37,41,43,53,59,97,89,109,79,73,71,31,29
5.divide by primes
you can remember first M primes in some array (for example first 100 primes)
and divide by them
and the use
for (nn=sqrt(n),i=last prime+2;i<=nn;i++) ...
also you can remember all primes computed on runtime in some list and use them
6.you can combine all above all together
7.there are many other ways to improve performance of is_prime(n) ?
so study if you need more speed
According to the operator precedence in C++
% has more priority than ==
so you should be using
if((n%i)==0)
good luck!