Jack Wetherell
Jack Wetherell

Reputation: 585

Get Segmentation Fault Occasionally

I am trying to make a random number generator for a uni project.

I am trying to implement a function to get the period of this list of numbers generated (how long before the numbers start to repeat).

When I compile this and run it it returns 507 (which is the correct period).

Yet about 50% of the time it returns a Segmentation Fault. Any idea what is happening:

#include<iostream>
#include<fstream>
#include<vector>
#include<math.h>
#include<ctime>

using namespace std;

class Random
{
public:
// Constructor
Random(int a, int b, int m)
{
    this->setMagicNumbers(a,b,m);
}

// Function to set the magic numbers of the random number generator
void setMagicNumbers(int a, int b, int m)
{
    this->A = a;
    this->B = b;
    this->M = m;
}

// Function that returns a list of uniformly distributed random numbers
vector<double> GetUniform(int N, double initialValue = time(0))
{
    double currentNumber = initialValue;
    vector<double> RandomNumbers;
    for(int i = 0; i <= N; i++)
    {
        currentNumber = fmod((this->A*currentNumber) + this->B, this->M);
        RandomNumbers.push_back(currentNumber / this->M); // The number is normalised here
    }
    return RandomNumbers;
}

private:
int A, B, M;
};

class NumberList
{
public:
// Function to add an element to the list
void push(double x)
{
    this->v.push_back(x);
}

// Function to pop an element off the list
double pop()
{
    if(v.size() > 0)
    {
        int popped = v.back();
        v.pop_back();
        return popped;
    }
    else
    {
        cout << "Cannot pop element off empty list." << endl;
        return 0;
    }
    return 0;
}

// Function to get the value at a given location on the list
double getAt(int i)
{
    return this->v[i];
}

    // Function to set the value at a given location on the list
void setAt(int i, double value)
{
    this->v[i] = value;
}

// Function to find the size of the list
unsigned int size()
{
    return this->v.size();
}

// Function to get the vector itself
vector<double> getvector()
{
    return this->v;
}

// Function to set the value of the vector itself
void setVector(vector<double> vec)
{
    this->v = vec;
}

// Function to print the list of numbers as coordinates to a data file
void printCoordinates()
{
        ofstream data("coordinates.dat");
        for(unsigned int i = 0; i <= this->v.size(); i++)
        {
                data << this->v[i] <<  " " << this->v[i + 1] <<  "\n";
        }
        data.close();
}

// Function to print the list of numbers to the terminal
void print()
{
        for(unsigned int i = 0; i <= this->v.size(); i++)
        {
                cout << this->v[i] << endl;
        }
}

// Function to get the period of the list of numbers
int getPeriod()
{
    int i = 2;
    while(true)
    {
        if(isPeriod(i) == true)
        {
            return i;
        }
        else
        {
            i = i + 1;
        }
    }
}

private:
// Vector to hold the values for the list
vector<double> v;

// Function to test if 'i' is the period of the list
bool isPeriod(int i)
{
    for(int j = 0; j != (i-1); j++)
    {
        if(this->getAt(j) != this->getAt(i + j))
        {
            return false;
        }
    }
    return true;
}
};

int main()
{
Random RandNumGenerator(100,104001,714025);                // Create a new random number generator with given magic numbers
NumberList numbers;                                        // Create a blank list of numbers
numbers.setVector(RandNumGenerator.GetUniform(10000));     // Add 10000 random numbers to the list
numbers.printCoordinates();                                // Print out the random numbers as coordinates to a data file
cout << numbers.getPeriod() << endl;                       // Print out the period of the random number list
return 0;
}

Thanks in advance.

Upvotes: 1

Views: 666

Answers (3)

imreal
imreal

Reputation: 10368

This line could cause a problem

for(unsigned int i = 0; i <= this->v.size(); i++)

With it you are using size as the last index, which is overflow, try changing it for this:

EDIT: change for this actually

for(unsigned int i = 0; i < this->v.size()-1; i++)

On the loop you are accessing the i+1 th element of the vector.

EDIT:

This probably wouldn't cause a crash but instead of creating N elements you are creating N+1

for(int i = 0; i <= N; i++)

Change if for this:

for(int i = 0; i < N; i++)

EDIT: With fixes

#include<iostream>
#include<fstream>
#include<vector>
#include<math.h>
#include<ctime>

using namespace std;

class Random
{
public:
// Constructor
Random(long a, long b, long m)
{
    this->setMagicNumbers(a,b,m);
}

// Function to set the magic numbers of the random number generator
void setMagicNumbers(long a, long b, long m)
{
    this->A = a;
    this->B = b;
    this->M = m;
}

// Function that returns a list of uniformly distributed random numbers
vector<double> GetUniform(int N, double initialValue = time(0))
{
    double currentNumber = initialValue;
    vector<double> RandomNumbers;
    for(int i = 0; i < N; i++)
    {
        currentNumber = fmod((this->A*currentNumber) + this->B, this->M);
        RandomNumbers.push_back(currentNumber / this->M); // The number is normalised here
    }
    return RandomNumbers;
}

private:
long A, B, M;
};

class NumberList
{
public:
// Function to add an element to the list
void push(double x)
{
    this->v.push_back(x);
}

// Function to pop an element off the list
double pop()
{
    if(v.size() > 0)
    {
        int popped = v.back();
        v.pop_back();
        return popped;
    }
    else
    {
        cout << "Cannot pop element off empty list." << endl;
        return 0;
    }
    return 0;
}

// Function to get the value at a given location on the list
double getAt(int i)
{
    return this->v[i];
}

    // Function to set the value at a given location on the list
void setAt(int i, double value)
{
    this->v[i] = value;
}

// Function to find the size of the list
unsigned int size()
{
    return this->v.size();
}

// Function to get the vector itself
vector<double> getvector()
{
    return this->v;
}

// Function to set the value of the vector itself
void setVector(vector<double> vec)
{
    this->v = vec;
}

// Function to print the list of numbers as coordinates to a data file
void printCoordinates()
{
        ofstream data("coordinates.dat");
        for(unsigned int i = 0; i < this->v.size()-1; i++)
        {
                data << this->v[i] <<  " " << this->v[i + 1] <<  "\n";
        }
        data.close();
}

// Function to print the list of numbers to the terminal
void print()
{
        for(unsigned int i = 0; i < this->v.size(); i++)
        {
                cout << this->v[i] << endl;
        }
}

// Function to get the period of the list of numbers
int getPeriod()
{
    int i = 2;
    while(true)
    {
        if(isPeriod(i) == true)
        {
            return i;
        }
        else
        {
            i = i + 1;
        }
    }
}

private:
// Vector to hold the values for the list
vector<double> v;

// Function to test if 'i' is the period of the list
bool isPeriod(int i)
{
    std::cout << "trying period " << i << endl;
    if (i >= v.size()) return true;
    for(int j = 0; j < v.size()-1; j++)
    {
        if(this->getAt(j) == this->getAt(i + j))
        {
            std::cout << "value at j " << this->getAt(j) << "value at i+j " << this->getAt(i+j) <<endl;
            return true;
        }
    }
    return false;
}
};

int main()
{
Random RandNumGenerator(100,104001,714025);                // Create a new random number generator with given magic numbers
NumberList numbers;                                        // Create a blank list of numbers
numbers.setVector(RandNumGenerator.GetUniform(10000));     // Add 10000 random numbers to the list
numbers.printCoordinates();                                // Print out the random numbers as coordinates to a data file
cout << numbers.getPeriod() << endl;                       // Print out the period of the random number list
return 0;
}

Upvotes: 3

BigBoss
BigBoss

Reputation: 6914

In C++ index of array and vector will be from 0..size - 1, and you misused it all over your code(inside GetUniform, inside printCoordinates, ...) and beside that in printCoordinates you written this->v[i + 1] at last it will be converted to this->v[this->v.size() + 1] that is 2 index after last valid index.

But I think source of your error is in getPeriod and isPeriod, look at it you start from 0 to i - 1 and check if that index match item at index i + j, so if i become size() - 1 and size be 500, then in worse case you are accessing v[499 + 498] that is really large than last valid index and you certainly get a segmentation fault. Now to solve it check your index and never go beyond end of the vector size, that mean you should never use index > v.size() - 1

Upvotes: 0

Component 10
Component 10

Reputation: 10497

Played around with this a bit and I initially thought that your vector of doubles was somehow getting corrupted. I found that if you size it to the exact value that you want - which is a known value - the seg faults stop:

vector<double> RandomNumbers(N); // In GetUniform()

Running it through gdb was inconclusive as it looked as if the stack was getting corrupted. I also found that when I changed the push_back() just to take 0:

RandomNumbers.push_back(0.0);

instead of the normalised number, even without the initial size for the vector (above) it worked fine, suggesting an issue with one of the variables being used.

I also found that if I set currentNumber to 1, say, instead of calling fmod() - even with everything as it originally was, I got no seg faults:

currentNumber = 1;

This kind of suggests that it might be something to do with the use of fmod()

Interestingly, I then took out the call to push_back completely and found that it still had segfaults. Sorry I can't be much more help than that, but it certainly looks as if some kind of corruption is happening somewhere in this area.

Upvotes: 0

Related Questions