why my code work in small instances only? - c++

I have developed a code for my problem and it seems like it is working but when I increase the problem size, it does not output anything. in my problem I have several courses with multiple meetings each week with a condition of each course must have at least one overall in all weeks(e.g. in a 4 weeks case, atleast one meeting in 4 weeks combined).
A sample of decired out put with 4 courses and 4 weeks looks like the following:
0, 0, 2, 0,
1, 0, 0, 0,
0, 1, 0, 1,
0, 2, 0, 3,
I have written the following recursive code and it is working for small number of courses and weeks but when I increase these number it does not output anything. even for small cases sometime it does not output anything and I have to run it againg to get a result. here is my code:
//headers
#include <iostream>
//global parameters
const int NumberOfCourses = 4;
const int AvailableWeeks = 4;
double Desired[NumberOfCourses][AvailableWeeks];
//parameters deciding how many courses should we remove from schedule
//option 0:0 f2f meeting
//option 1:1 f2f meeting
//option 2:2 f2f meeting
//option 3:3 f2f meeting
const double DN_possibilites[4] = { 0.7, 0.15, 0.1, 0.05 };
double Rand;
long int OptionSelected;
double SumOfProbabiltiesSofar = 0;
double total = 0;
int c, w;
using namespace std;
void DN_generator() {
long int currSysTime = time(NULL);
srand(currSysTime);
for (int c = 0; c < NumberOfCourses; c++) {
for (int w = 0; w < AvailableWeeks; w++) {
long int currSysTime = time(NULL);
Rand = ((float)rand() / RAND_MAX);
//cout << Rand << endl;
long int OptionSelected;
double SumOfProbabiltiesSofar = 0;
for (int i = 0; i < 4; i++) {
SumOfProbabiltiesSofar += DN_possibilites[i];
if (Rand < SumOfProbabiltiesSofar) {
OptionSelected = i;
break;
}
}
if (OptionSelected == 0) {
Desired[c][w] = 0;
}
else if (OptionSelected == 1) {
Desired[c][w] = 1;
}
else if (OptionSelected == 2) {
Desired[c][w] = 2;
}
else if (OptionSelected == 3) {
Desired[c][w] = 3;
}
}
}
for (c = 0; c < NumberOfCourses; c++) {
total = 0;
for (w = 0; w < AvailableWeeks; w++) {
total += Desired[c][w];
}
if (total == 0) {
DN_generator();
}
}
}
int main(){
DN_generator();
for (c = 0; c < NumberOfCourses; c++) {
for (w = 0; w < AvailableWeeks; w++) {
cout << Desired[c][w] << ", ";
}
cout << endl;
}
return 0;
}
any help is much appreciated.

I see at least four fundamental flaws in the shown code:
With the random seed getting reset to the system clock on every recursive iteration, every call to the recursive function within the same second will produce the same results. If any one of them results in a total sum of 0, the recursive function repeats and produces the same results. The simple code can run fast enough on modern CPUs to blow through the stack, and crash, in much less than the second.
Increasing the array size increases the chances of the first problem happening. The combination of these two factors is what results in the crash, but that's not the end of the problems in the shown code.
If the total sum is 0, a recursive call is made. When the recursive call returns, it happily resumes totaling all the remaining rows, which makes no logical sense. This is a flaw in the recursion algorithm
Finally, the shown code has guaranteed undefined behavior:
SumOfProbabiltiesSofar += DN_possibilites[i];
The assumption in this line of the code is that on the last iteration SumOfProbabiltiesSofar becomes 1.0 and the following if statement's condition is guaranteed to evaluate to true. This is not true because floating point math is broken.
With the sufficiently large number of iteration it becomes likely that the random value will be enough close to 1 so that exceeds the almost-1.0 value that ends up being here. The for loop exits without initializing OptionSelected, resulting in undefined behavior. This logic must be fixed too.
All of these problems will need to be fixed before the shown algorithm works correctly.

Related

Compiler optimization on the traveling salesman problem

I am playing with the travelling salesman problem and am looking at the version where:
the towns are points in 2d space and there are paths from every town to all others and the lengths are the distances between the points. So it's very easy to implement the naive solution where you check all permutations of n points and calculate the length of the path.
I've found however that for n >= 10 the compiler does some magic and prints a value that is certainly not the actual shortest path. I compile with the Microsoft visual studio compiler in release mode with the default settings. For values (10,30) it thinks for 30 seconds and then returns some number that seems like it could be correct but it is not (I check in different ways). And for n > 40 it calculates a result immediately and is always 2.14748e+09.
I am looking for an explanation to what does the compiler do in the different situations (the (10,30) case is really interesting). And an example where these optimizations are more useful than the program just spinning to the end of the world.
vector<pair<int,int>> points;
void min_len()
{
// n is a global variable with the number of points(towns)
double min = INT_MAX;
// there are n! permutations of n elements
for (auto j = 0; j < factorial(n); ++j)
{
double sum = 0;
for (auto i = 0; i < n - 1; ++i)
{
sum += distance_points(points[i], points[i + 1]);
}
if (sum < min)
{
min = sum;
s_path = points;
}
next_permutation(points.begin(), points.end());
}
for (auto i = 0; i < n; ++i)
{
cout << s_path[i].first << " " << s_path[i].second << endl;
}
cout << min << endl;
}
unsigned int factorial(unsigned int n)
{
int res = 1, i;
for (i = 2; i <= n; i++)
res *= i;
return res;
}
Your factorial function is overflowing. Try replacing it with one returning int64_t and see your code taking 3 years to terminate for n > 20.
constexpr uint64_t factorial(unsigned int n) {
return n ? n * factorial(n-1) : 1;
}
Also, you don't need to calculate this at all. The std::next_permutation function returns 0 when all permutations have occured (starting from sorted position).

(C++) Finding all prime numbers between two integers (without using sieve of Eratosthanes)

I'm trying to find all the prime numbers between two integers and place them in an integer array.
The catch is that i have to use a specific method of doing so (divide each subsequent integer by all the primes in my array). So I can't use the sieve of Eratosthanes or any other 'easier' methods.
My code successfully prompts the user for two integers, but for now I do not use either of them. First I want to make sure the program works for values between 0 and whatever, in this case 200 just to test it.
Problem is, when I run the program and print the first 20 or so values in the array, I'm getting
2, 3, 5, 7, 11, 200, 0, 0, 0, 0, 0, 0 ...... more zeroes.
The first 5 values are correct because they start in the array, but after that the whole thing goes haywire.
I've worked through my nested loop by hand for a couple values and it SEEMS like it should work. I feel like there's a specific array property that I'm overlooking.
Here's my code:
#include "stdafx.h"
#include "iostream"
#include "climits"
#include "cmath"
#include "array"
using namespace std;
int main()
{
// declare variables to store user input
int lowerBound, upperBound;
// prompt user for lesser and greater integers and store them
cout << "Program to find all primes between two integers." << endl;
cout << "Enter lesser integer: " << endl;
cin >> lowerBound;
cout << "Enter greater integer: " << endl;
cin >> upperBound;
// if statement to switch the input variables if the user accidentally enters them backwards
if (lowerBound > upperBound) {
int temp = lowerBound;
lowerBound = upperBound;
upperBound = temp;
}
// initialize int array with the first 5 primes
int primes[100] = { 2, 3, 5, 7, 11 };
// loop to find primes between 12 and 200 (since we already have primes from 1-11 in the array)
for (int i = 12; i <= 200; i++) {
// the maximum divisor needed to determine if the current integer being tested is prime
double maxDivisor = sqrt(i);
// variable for the current size of the array
int size = 5;
// boolean variable is set to true by default
bool isPrime = true;
for (int j = 0; j < size; j++) { // changed "j<=size" to "j<size"
int remainder = (i % primes[j]);
// once the maximum divisor is reached, there is no need to continue testing for the current integer
if (primes[j] > maxDivisor) {
break;
}
// if the remainder of divison by a prime is 0, the number is not prime, so set the boolean variable to false
if (remainder = 0) {
isPrime = false;
}
}
// if isPrime is still true after the nested loop, the integer value being tested will be placed in the next element of the array
if (isPrime == true) {
primes[size] = i;
// since we added to the array, increment size by 1
size++;
}
}
// display the first 20 values in the array for debugging
for (int k = 0; k < 20; k++) {
cout << primes[k] << ", ";
}
system("pause");
return 0;
}
This here
if (remainder = 0) {
isPrime = false;
}
Needs to be changed to
if (remainder == 0) {
isPrime = false;
}
Because = does assignment, not comparison. So what remainder = 0 does it setting remainder to 0, and then it returns that 0, which gets casted to false, which is on of the reasons why it's not finding any primes.
Also, as Fantastic Mr Fox pointed out, for (int j = 0; j <= size; j++) needs to be changed to for (int j = 0; j < size; j++).
Also, did your compiler issue any warnings? If not, try to see if you can set it to be more strict with warnings. I figure most modern compilers will give you a hint at if (remainder = 0). Getting useful warnings from the compiler helps a lot with preventing bugs.
Edit:
As Karsten Koop pointed out, you need to move the int size = 5; out of the loop, to before the for (int i = 12;. With those changes, it's now working on my machine.
Last but not least, a tip: instead of if (isPrime == true), you can just write if (isPrime).

How to debug my program that runs properly but returns segmentation fault in an ide?

using namespace std;
#include<iostream>
class biker
{
public:
int initspeed, acc, speeding;
};
void input(int n, biker a[])
{
for (int i = 0; i < n; i++)
{
//cout<<"Enter the initspeed:"<<"\n";
std::cin >> a[i].initspeed;
//cout<<"Enter the acceleration:"<<"\n";
std::cin >> a[i].acc;
}
}
int main()
{
int n = 0, i = 0, t = 0, max_speed = 0, flag = 0, minimum = 0;
biker a[100];
std::cin >> t;
for (int k = 0; k < t; k++)
{
//cout<<"Enter no of bikers"<<"\n";
std::cin >> n;
//cout<<"enter the max track speed"<<"\n";
std::cin >> max_speed;
//cout<<"Enter the min niker speed"<<"\n";
std::cin >> minimum;
input(n, a);
int j = 1, x = 0;
while (flag < 500)
{
int sum = 0;
for (i = 0; i < n; i++)
{
int prod = 0;
prod = a[i].acc * j;
x = a[i].initspeed + prod;
// cout<<"VAL"<<x<<"\n";
if (x >= minimum)
{
//cout<<"It is greater than minimum";
sum = sum + a[i].initspeed + prod;
//cout<<sum<<"\n";
}
}
if (sum >= max_speed)
{
//cout<<"MAXIMUM ACHIEVED\n";
x = sum;
break;
}
j++;
flag++;
}
//cout<<x<<"\n";
std::cout << j;
}
return 0;
}
The above code is my solution to the bike racing problem in geeksforgeeks.
Summary:
A Bike race is to be organized. There will be N bikers. You are given initial Speed of the ith Biker by Hi and the Acceleration of ith biker as Ai KiloMeters per Hour.
The organizers want the safety of the bikers and the viewers.They monitor the Total Speed on the racing track after every Hour.
A biker whose Speed is 'L' or more, is considered a Fast Biker.
To Calculate the Total speed on the track- They Add the speed of each Fast biker ,at that Hour.
As soon as The total speed on the track is 'M' KiloMeters per Hour or more, The safety Alarm buzzes.
You need to tell what is the minimum number of Hours after which the safety alarm will buzz.
Input:
The first Line contains T- denoting the number of test cases.
The first line of each test case contains three space-separated integers N, M and L denoting the number of bikers and speed limit of the track respectively, and A fast Biker's Minimum Speed.
Each of next N lines contains two space-separated integers denoting Hi and Ai respectively.
Output:
For each test case-Output a single integer denoting the minimum number of Hours after which alarm buzzes.
Constraints:
1<=T<=100
1<=N<=1e5
1 ≤ M,L ≤ 1e10
1 ≤ Hi, Ai ≤ 1e9
My code runs properly on my computer and also on the ide .But when i click submit, it crashes returning Segmentation fault(SIGSEGV).
The array a can contain at most 100 bikers. The problem statement specifies that the number of bikers can be up to 10,000.
Overrunning the end of the array invokes Undefined Behaviour (UB) which is manifesting as a segfault on the judging system. Either the UB is manifesting differently on your development system or you have not tested it with a sufficiently large number of bikers.

C++ Birthday Paradox Using a Boolean Function

I have an assignment where I need to calculate the probability that two people share the same birthday for a given room size (in my case 50) over many trials (5000). I have to assign the birthdays randomly to the number of people in the room. The difference is I need to use a Boolean function to check the if the Birthdays are the same. I cannot figure why my outputs are off, but I believe it has something to do with two of my loops.
>
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
bool SameBirthday(int birthdays[], int numpeople);
const int MAX_PEOPLE = 50;
const double NUM_TRIALS = 5000.0;
const int DAYS_IN_YEAR = 365;
int main(void)
{
int numMatches = 0;
int people = 2;
int trial = 0;
int numpeople = 0;
int i = 0;
int birthdays[MAX_PEOPLE];
bool Match;
double Probability = 0;
srand(time(0));
for (people = 2; people <= MAX_PEOPLE; people++)
{
numMatches = 0;
for (trial = 0; trial < NUM_TRIALS; trial++)
{
for (i = 0; i < people; i++)
{
birthdays[i] = (rand() % 365 + 1);
numpeople = i;
}
if ((SameBirthday(birthdays, numpeople) == true))
{
numMatches++;
}
}
Probability = (numMatches / NUM_TRIALS);
cout << "For " << people << ", the probability of two birthdays is about " << Probability << endl;
}
}
bool SameBirthday(int birthdays[], int numpeople)
{
bool match = false;
int numberofmatches = 0;
//Use this function to attempt to search the giving array birthdays and count up number of times
//at least two people have matching birthdays for any given 1 trial
for (int SpaceOne = 0; SpaceOne < numpeople; SpaceOne++)
{
for (int SpaceTwo = SpaceOne + 1; SpaceTwo < numpeople; SpaceTwo++)
{
if (birthdays[SpaceTwo] == birthdays[SpaceOne])
{
return true;
}
}
}
return false;
}
I know that the code has errors in certain spots that was because I started trying different things, but any help would be appreciated.
EDIT- My only issue now is that for my output I have a zero for the probability of 2 people in the room have a birthday, which is not right. It seems like my outputs are like a person off, the probability of 2 people is shown as the probability for three people and so on.
EDIT(8-31-2015): I also forgot to mention that my Professor stated that my SameBirthday function needed the parameters: birthday[], and numpeople so I cannot use MAX_PEOPLE as a parameter. My professor also suggested using a triple nested for loop within the main body of the function. I believe what is making my output off by one for each person relates to the triple nested for loop, but I am unsure what would cause the issue.
Just do it like this:
bool SameBirthday(int birthdays[], int numPeople)
{
for(int x=0; x<numPeople; x++){
for(int y=0; y<numPeople; y++){
if(birthdays[x] == birthdays[y])
return true;
}
}
return false;
}
Your logic in your nested loop is wrong..
for (SpaceOne = 0; SpaceOne < numpeople - 1; SpaceOne++)
for (SpaceTwo = SpaceOne + 1; SpaceTwo < numpeople; SpaceTwo++)
Your inner loop is skipping n number of checks where n equals SpaceOne.
By the way, this is not C programming. You can declare variable within a for-loop.
I see two problems with the actual functionality. First, SameBirthday needs to return a value (false) when there is no birthday match. You can do that at the end of the function, after all the loops are done.
Second, you need to increment numMatches when you find a match.
To clarify issues from other parts of your coding. I think this is what your school wants.
int main(){
//All your variables
for(int x=0; x<NUM_TRIALS; x++){
for(int y=0; y< MAX_PEOPLE; y++){
birthdays[y] = (rand() % 365 + 1);
}
if(SameBirthday(birthdays, MAX_PEOPLE) == true)
numMatches ++;
}
Probability = ((double)numMatches / NUM_TRIALS);
cout << "For " << people << ", the probability of two birthdays is about "
<< Probability << endl;
}
NUM_TRIALS to generate 5000 datasets. Hence, you generate birthday for 50 students 5000 times. For each trial within a class of 50, you check whether there are 2 person with same birthday. If there is, numMatches + 1.
After 5000 trials, you get the probability.
Your other problem is that numpeople will always be the number of people minus 1. You don't actually need that variable at all. Your "people" variable is the correct number of people.

weighted RNG speed problem in C++

Edit: to clarify, the problem is with the second algorithm.
I have a bit of C++ code that samples cards from a 52 card deck, which works just fine:
void sample_allcards(int table[5], int holes[], int players) {
int temp[5 + 2 * players];
bool try_again;
int c, n, i;
for (i = 0; i < 5 + 2 * players; i++) {
try_again = true;
while (try_again == true) {
try_again = false;
c = fast_rand52();
// reject collisions
for (n = 0; n < i + 1; n++) {
try_again = (temp[n] == c) || try_again;
}
temp[i] = c;
}
}
copy_cards(table, temp, 5);
copy_cards(holes, temp + 5, 2 * players);
}
I am implementing code to sample the hole cards according to a known distribution (stored as a 2d table). My code for this looks like:
void sample_allcards_weighted(double weights[][HOLE_CARDS], int table[5], int holes[], int players) {
// weights are distribution over hole cards
int temp[5 + 2 * players];
int n, i;
// table cards
for (i = 0; i < 5; i++) {
bool try_again = true;
while (try_again == true) {
try_again = false;
int c = fast_rand52();
// reject collisions
for (n = 0; n < i + 1; n++) {
try_again = (temp[n] == c) || try_again;
}
temp[i] = c;
}
}
for (int player = 0; player < players; player++) {
// hole cards according to distribution
i = 5 + 2 * player;
bool try_again = true;
while (try_again == true) {
try_again = false;
// weighted-sample c1 and c2 at once
// h is a number < 1325
int h = weighted_randi(&weights[player][0], HOLE_CARDS);
// i2h uses h and sets temp[i] to the 2 cards implied by h
i2h(&temp[i], h);
// reject collisions
for (n = 0; n < i; n++) {
try_again = (temp[n] == temp[i]) || (temp[n] == temp[i+1]) || try_again;
}
}
}
copy_cards(table, temp, 5);
copy_cards(holes, temp + 5, 2 * players);
}
My problem? The weighted sampling algorithm is a factor of 10 slower. Speed is very important for my application.
Is there a way to improve the speed of my algorithm to something more reasonable? Am I doing something wrong in my implementation?
Thanks.
edit: I was asked about this function, which I should have posted, since it is key
inline int weighted_randi(double *w, int num_choices) {
double r = fast_randd();
double threshold = 0;
int n;
for (n = 0; n < num_choices; n++) {
threshold += *w;
if (r <= threshold) return n;
w++;
}
// shouldn't get this far
cerr << n << "\t" << threshold << "\t" << r << endl;
assert(n < num_choices);
return -1;
}
...and i2h() is basically just an array lookup.
Your reject collisions are turning an O(n) algorithm into (I think) an O(n^2) operation.
There are two ways to select cards from a deck: shuffle and pop, or pick sets until the elements of the set are unique; you are doing the latter which requires a considerable amount of backtracking.
I didn't look at the details of the code, just a quick scan.
you could gain some speed by replacing the all the loops that check if a card is taken with a bit mask, eg for a pool of 52 cards, we prevent collisions like so:
DWORD dwMask[2] = {0}; //64 bits
//...
int nCard;
while(true)
{
nCard = rand_52();
if(!(dwMask[nCard >> 5] & 1 << (nCard & 31)))
{
dwMask[nCard >> 5] |= 1 << (nCard & 31);
break;
}
}
//...
My guess would be the memcpy(1326*sizeof(double)) within the retry-loop. It doesn't seem to change, so should it be copied each time?
Rather than tell you what the problem is, let me suggest how you can find it. Either 1) single-step it in the IDE, or 2) randomly halt it to see what it's doing.
That said, sampling by rejection, as you are doing, can take an unreasonably long time if you are rejecting most samples.
Your inner "try_again" for loop should stop as soon as it sets try_again to true - there's no point in doing more work after you know you need to try again.
for (n = 0; n < i && !try_again; n++) {
try_again = (temp[n] == temp[i]) || (temp[n] == temp[i+1]);
}
Answering the second question about picking from a weighted set also has an algorithmic replacement that should be less time complex. This is based on the principle of that which is pre-computed does not need to be re-computed.
In an ordinary selection, you have an integral number of bins which makes picking a bin an O(1) operation. Your weighted_randi function has bins of real length, thus selection in your current version operates in O(n) time. Since you don't say (but do imply) that the vector of weights w is constant, I'll assume that it is.
You aren't interested in the width of the bins, per se, you are interested in the locations of their edges that you re-compute on every call to weighted_randi using the variable threshold. If the constancy of w is true, pre-computing a list of edges (that is, the value of threshold for all *w) is your O(n) step which need only be done once. If you put the results in a (naturally) ordered list, a binary search on all future calls yields an O(log n) time complexity with an increase in space needed of only sizeof w / sizeof w[0].