I currently have a C++ program which is supposed to generate every possible domain name up to a set number of digits. The code I have is current pretty verbose (this is fine) but also tediously slow once it starts generating past 4 digits. The loops where things really start to go wrong are shown here:
const char* chars[] = {"a","b","c","d","e","f","g","h","i","j","k",
"l","m","n","o","p","q","r","s","t","u","v","w","x","y","z", "0", "1",
"2", "3", "4", "5", "6", "7", "8", "9", "-"};
int char_num = 1;
[...]
if(char_num == 5) {
for(int i = 0; i < 36; i++) {
for(int j = 0; j < 37; j++) {
for(int k = 0; k < 37; k++) {
for(int l = 0; l < 37; l++) {
for(int m = 0; m < 36; m++) {
cout << "adding " << chars[i] << chars[j] << chars[k] << chars[l] << chars[m] << ".com to list\n";
if(i == 35 && j == 36 && k == 36 && l == 36 && m == 35) {
char_num++;
cout << "Generating to " << char_num + 1 << " characters\n";
}
}
}
}
}
}
}
I am intending at least three or four additional if statements after this one, with incrementally more for loops in each. I'm also going to need to write the output to a file, and to use this file to do DNS lookups, so I need every drop of performance I can get so I'm not waiting weeks for the program to complete.
My main concern at present is that the program is evaluating the if statement on every single interation which I presume is having a significant effect on performance, given the number of nested loops. To stop this I tried moving the if statement into a separate function and having it return a value once it finished, but I noticed that when I do this I'm not able to log to the console from within the function, which makes things more complicated.
What is the correct process for doing this in C++ and are there any other ways to speed up the code? I did try writing the code in node.js before but it went berserk and threw a bunch of out of memory errors when I started writing to a file, and I figured C++ would probably be quicker anyway, hence I switched languages.
Your if statement seems to be checking for the end of the loop. There is a simple solution to avoid this: remove the if and put the code after the loop!
However, if you need to add more ifs that depend on loop variables, I don't really know how you can optimize it. Don't, however, put them in a function: the overhead of calling the function will slow your code (and an optimizing compiler will inline your function anyway).
Here are a few possibilities you can explore:
use multithreading/multiprocessing. If done well, this can divide the execution time by up to the number of CPU cores on your computer
enable compiler optimization (-O3 or -Ofast with g++)
One last thing: if the consumer program accepts data from the standard input, piping the output of your program into it will be twice as fast as generating the names then using them. EG instead of
producer > storage.txt
consumer < storage.txt
do
producer | consumer
Focus on code optimizations. In the statement you are constantly re accessing the same member of the char array every iteration wasting clock cycles.
`cout << "adding " << chars[i] << chars[j] << chars[k] << chars[l] << chars[m] << ".com to list\n";`
A way to optimize this is by adding temporary variables.
char tempI;
char tempJ;
char tempK;
char tempL;
if(char_num == 5) {
for(int i = 0; i < 36; i++) {
tempI = char[i];
for(int j = 0; j < 37; j++) {
tempJ = char[j];
for(int k = 0; k < 37; k++) {
tempK = char[k];
for(int l = 0; l < 37; l++) {
tempL = char[l];
for(int m = 0; m < 36; m++) {
cout << "adding " << tempI << tempJ << tempK << tempL <<
chars[m] << ".com to list\n";
if(i == 35 && j == 36 && k == 36 && l == 36 && m == 35) {
char_num++;
cout << "Generating to " << char_num + 1 << " characters\n";
}
}
}
}
}
}
}
There are things you can do that make your code faster in regards to temporal and spatial locality just by the way you write it.
Also use compiler optimizations -03 with g++, etc.
Or consider rewriting your algorithm, because there might be a better way altogether in regards to time complexity
Related
I'm coming from C into C++, I might be missing something very basic.
I'm trying to make a program with the collatz conjecture.
Before the first iteration of the loop, i and j both correctly equal 1 and 10.
However, the value of i never seems to change although I have i++ in my loop.
I thought this would be a quick program to code but I'm getting hung up on this. Any help would be appreciated.
int n, j, i, count = 0;
cin >> n >> j;
for (i = n; i < j; i++){
while (i != 1){
if (i % 2 == 0)
i = i/2;
else
i = 3*i + 1;
}
count++;
cout << i << endl;
}
The problem in your code is that after you've run the while loop that tests whether the conjecture is true for i, i is by definition set back to 1 (since that's the condition to get out of the loop), so i++ keeps incrementing from 1 to 2 each time. You'll never get past 2.
If you're trying to test the Collatz Conjecture for all the numbers from n to j, you need to use a different variable in the while loop than you use for iteration.
And if count is supposed to tell you how many cycles are needed, you need to zero it before each while loop, and increment it inside the while loop.
int n, j, i;
cin >> n >> j;
for (i = n; i < j; i++){
int test = i;
int count = 0;
while (test != 1){
if (test % 2 == 0) {
test = test/2;
} else {
test = 3*test + 1;
}
count++;
}
cout << i << ' ' << count << endl;
}
Not sure what it's all about, but here's some quick observation:
your while(i != 1) loop means that it will either run indefinetely, or when this loop ends i will be equal to 1. Which means that your for (i = n; i < j; i++){ loops will always restart with i=1. No wonder it's a dead loop.
Before the first iteration of the loop, i and j both correctly equal 1 and 10.
The let's replay the second iteration of the outer loop.
Before it, at the end of the first iteration, i has been incremented to equal 2. Now,
i % 2 == 0 => i := i / 2, i.e. i := 1.
Now i == 1, inner loop ends.
i is incremented and now equals 2.
Repeat.
You can simply copy the loop variable to a new variable in every loop iteration i = k in this case, so that the for loop variable is not affected
#include <iostream>
int main(){
int min, max, count = 0;
std::cin >> min >> max;
for (int k = min; k <= max; ++k){
i = k;
while (i != 1)
{
if (i % 2 == 0)
i /= 2;
else
i = 3*i + 1;
count++;
std::cout << i << std::endl; //ONLY IF U WANT TO PRINT i EVERY ITERATION
}
std::cout << "Number of iterations needed: " << count << " for i = " << i << std:: endl;
}
I am new to competitive coding (C++) and was Practising on hackerEarth problems based on Implementation . I submitted a problem to find summations of an array in 3 diff. parts .
Here's My code it took 1.010039s to execute:
int main()
{
long unsigned int n, a[100000], s1 = 0, s2 = 0, s3 = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (i % 3 == 0)
s3 = s3 + a[i];
else if ((i - 2) % 3 == 0)
s2 = s2 + a[i];
else
s1 = s1 + a[i];
}
cout << s1 << " " << s2 << " " << s3;
return 0;
}
Here's The Least Time code :
int main()
{
int n;
long unsigned int a[100000];
long unsigned int s1 = 0, s2 = 0, s3 = 0;
int i;
cin >> n;
for (i = 0; i < n; i++) {
cin >> a[i];
}
for (i = 0; i < n; i = i + 3) {
s1 = s1 + a[i];
}
for (i = 1; i < n; i = i + 3) {
s2 = s2 + a[i];
}
for (i = 2; i < n; i = i + 3) {
s3 = s3 + a[i];
}
cout << s1 << " " << s2 << " " << s3 << endl;
return 0;
}
we can see that ,there are much more for loops in the second case , and still it is faster why ?
it doesn't matter how many loops you write as long as they don't overlap.
the real factor which made the second algorithm faster is that in each time index i is moving 3 times not like the first algorithms (step by step) you may also consider the ifs that will make a bit of change in huge data entry as you know in competitive programming every millisecond counts.
for that i would recommend you to study Complexity that will help you with your competitive passion as it did for me.
The least time code is non-branching (except for the loop condition). That mean the compiler knows exactly what will happen, which instruction will be executed. It also means the CPU knows what instruction are coming and what will be executed. That allows the best instructions to be generated by the compiler and allows the CPU to fetch the right memory and prepare itself for what's coming.
As a result, the whole CPU is fully utilized most of the time.
In your case, the result of i%3 can't be predicted, so the CPU stalls as it didn't always plan correctly which branch of the ifs it would take. In fact, your code is better for cache locality as it touches contiguous memory just once. But you get a much bigger performance hit from the branching part.
As a general rule: the least ifs in your code, the faster it can be.
Why are increment statements a thing in for-loops in C++? To me it seems redundant, because you could simply put the increments inside the conditional code. Am I misunderstanding something important here?
To illustrate my question better, I'm including some pseudocode:
What is the difference between ->
for( int a = 10; a < 20; a = a + 1 )
{
cout << a << endl;
}
and
for( int a = 10; a < 20;)
{
a = a + 1
cout << a << endl;
}
It's more than mere convenience sometimes.
These are equivalent:
for (int a = 10; a < 20; a = a + 1) {
cout << a << endl;
}
for (int a = 10; a < 20; ) {
cout << a << endl;
a = a + 1;
}
But, these are not:
// this works ...
for (int a = 10; a < 20; a = a + 1) {
if (blah ...)
continue;
cout << a << endl;
}
// this doesn't
for (int a = 10; a < 20; ) {
if (blah ...)
continue;
cout << a << endl;
a = a + 1;
}
Since you're coming from python, an idiomatic for loop is like a python range, but much more powerful. Your C for loop, expressed in python would be:
for a in range(10,20,1)
It's more idiomatic to express this as:
for (a = 10; a < 20; a += 1)
Because the loop increment is 1, it's even more idiomatic to do this:
for (a = 10; a < 20; ++a)
But, for loops are:
for ([init_stmt]; [test_stmt]; [incr_stmt])
Where any of the *_stmt can be compound:
for (x = 0, y = 0; x < 10; ++x, y += 2)
Convenience.
However, your equivalent code should be:
for (int a = 10; a < 20;)
{
cout << a << endl;
a = a + 1;
}
It runs at the end of the loop body.
[ snips grumbling about quality of now deleted/ edited answers ;-) ]
This:
for (unsigned counter = 1; counter <= 10; ++counter) {
doStuff();
}
is largely equivalent to this:
unsigned counter = 1;
while (counter <= 10) {
doStuff();
++counter;
}
with the notable exception that, in the 1st case, you have the considerable benefit that counter is scoped only to within the for block and automatically goes out-of-scope as soon as it finishes - whereas with the latter, counter must remain in-scope after the loop, where it's potentially useless or even an obstacle.
(tangential: Note that C did not support within-for declaration, or any non-top-of-block declarations, until C99 - but barring extenuating circumstances, anyone not using at least C99 by now is making a questionable choice imho.)
edit: Craig also makes a very good point regarding continue - an oft-forgotten but certainly useful statement. I'm sure there are probably other differences we could conjure up.
for this example:
using namespace std;
int main(int argc, char** argv) {
for( int a = 10; a < 20;)
{
a = a + 1;
cout << a << endl;
}
return 0;
}
the output will be from 11-->20
the first example will be from 10-->19
your are putting the increment part outside the loop and this possible, but notice that the value 10 will not appear, because you are increment before printing the value of a
so in the 2nd example your printing the value and then increment, and at the end of the loop, you are quiting the loop without reaching 20, because the condition get you out the loop
executing code block before increment is the key for you, the for loop increment just after the code block is executed
Well it is not required, it is just for convenience.
In your second code, you made a little mistake which would make the code nonequivalent to the the first one.
Your increment should be at the end of loop in order to be equivalent to the first code
so it should rather be:
for( int a = 10; a < 20;)
{
cout << a << endl;
a = a + 1; //increment at the end of instructions
}
These little errors and also errors like forgetting to include your increment is why it is convenient to include the increment in the for loop.
Or you can use the while loop instead:
while (condition)
{//instructions here;}
I'm trying to write a program for university. The goal of the program is to make a nurse schedule for a hospital. However, i'm really stuck for the moment. Below you can find one function of the program.
The input for the function is a roster which consists of the shift each nurse has to perform on each day. In this example, we have 32 rows (32 nurses) and 28 columns (representing 28 days). Each cell contains a number from 0 to 6, indicating a day off (0) or a certain shift (1 to 6).
The function should calculate for each day, how many nurses are scheduled for a certain shift. For example, on the first day, there are 8 nurses which perform shift 2, 6 shift 3 and so forth. The output of the function is a double vector.
I think the function is mostly correct but when I call it for different rosters the program always gives the first roster gave.
void calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
for (int i = 0; i < get_nbr_days(); i++)
{
vector<int> nurses_per_shift;
int nbr_nurses_free = 0;
int nbr_nurses_shift1 = 0;
int nbr_nurses_shift2 = 0;
int nbr_nurses_shift3 = 0;
int nbr_nurses_shift4 = 0;
int nbr_nurses_shift5 = 0;
int nbr_nurses_shift6 = 0;
for (int j = 0; j < get_nbr_nurses(); j++)
{
if (roster1[j][i] == 0)
nbr_nurses_free += 1;
if (roster1[j][i] == 1)
nbr_nurses_shift1 += 1;
if (roster1[j][i] == 2)
nbr_nurses_shift2 += 1;
if (roster1[j][i] == 3)
nbr_nurses_shift3 += 1;
if (roster1[j][i] == 4)
nbr_nurses_shift4 += 1;
if (roster1[j][i] == 5)
nbr_nurses_shift5 += 1;
if (roster1[j][i] == 6)
nbr_nurses_shift6 += 1;
}
nurses_per_shift.push_back(nbr_nurses_shift1);
nurses_per_shift.push_back(nbr_nurses_shift2);
nurses_per_shift.push_back(nbr_nurses_shift3);
nurses_per_shift.push_back(nbr_nurses_shift4);
nurses_per_shift.push_back(nbr_nurses_shift5);
nurses_per_shift.push_back(nbr_nurses_shift6);
nurses_per_shift.push_back(nbr_nurses_free);
nbr_nurses_per_shift_per_day.push_back(nurses_per_shift);
}
}
Here you can see the program:
Get_shift_assignment() and schedule_LD are other rosters.
void test_schedule_function()
{
calculate_nbr_nurses_per_shift(schedule_LD);
calculate_nbr_nurses_per_shift(get_shift_assignment());
calculate_coverage_deficit();
}
One more function you need to fully understand the problem is this one:
void calculate_coverage_deficit()
{
int deficit = 0;
for (int i = 0; i < get_nbr_days(); i++)
{
vector<int> deficit_day;
for (int j = 0; j < get_nbr_shifts(); j++)
{
deficit = get_staffing_requirements()[j] - nbr_nurses_per_shift_per_day[i][j];
deficit_day.push_back(deficit);
}
nurses_deficit.push_back(deficit_day);
}
cout << "Day 1, shift 1: there is a deficit of " << nurses_deficit[0][0] << " nurses." << endl;
cout << "Day 1, shift 2: there is a deficit of " << nurses_deficit[0][1] << " nurses." << endl;
cout << "Day 1, shift 3: there is a deficit of " << nurses_deficit[0][2] << " nurses." << endl;
cout << "Day 1, shift 4: there is a deficit of " << nurses_deficit[0][3] << " nurses." << endl;
}
So the problem is that each time I run this program it always gives me the deficits of the first roster. In this case, this is Schedule_LD. When I first run the function with input roster get_shift_assignment() than he gives me the deficits for that roster.
Apparently the nbr_nurses_per_shift_per_day[][] vector is not overwritten the second time I run the function and I don't know how to fix this... Any help would be greatly appreciated.
Let me try to summarize the comments:
By using global variables to return values from your functions it is very likely, that you forgot to remove older results from one or more of your global variables before calling functions again.
To get around this, return your results from the function instead.
Ex:
vector<vector<int>> calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
vector<int> nbr_nurses_per_shift_per_day; // Create the result vector
... // Do your calculations
return nbr_nurses_per_shift_per_day;
}
or if you do not want to return a vector:
void calculate_nbr_nurses_per_shift(vector<vector<int>> roster1, vector<vector<int>> nbr_nurses_per_shift_per_day)
{
... // Do your calculations
}
But clearly, the first variant is a lot less error-prone (in the second example you can forget to clear nbr_of_nurses again) and most compilers will optimize the return nbr_nurses_per_shift_per_day so the whole vector does not get copied.
The second possible issue is that ´get_nbr_days()´ might return numbers that are larger or smaller than the actual size of your vector. To work around this, use either the size() method of vector or use iterators instead.
Your first function would then look like this:
vector<vector<int>> calculate_nbr_nurses_per_shift(vector<vector<int>> roster1)
{
vector<vector<int>> nbr_nurses_per_shift_per_day;
for (vector<vector<int>>::iterator shiftsOnDay = roster1.begin(); shiftsOnDay != roster1.end(); ++shiftsOnDay)
{
vector<int> nurses_per_shift(6, 0); // Create vector with 6 elements initialized to 0
for (vector<int>::iterator shift = shiftsOnDay->begin(); shift != shiftsOnDay->end(); ++shift)
{
if (*shift == 0)
nurses_per_shift[5]++;
else
nurses_per_shift[*shift - 1]++; // This code relies on shift only containing meaningful values
}
nbr_nurses_per_shift_per_day.push_back(nurses_per_shift);
}
return nbr_nurses_per_shift_per_day;
}
For this code I created that outputs the ASCII characters corresponding to ints, I need to print out 16 ASCIIs per line. How would I go about doing so? I'm not sure how to approach these? Do I create another for loop inside?
int main()
{
int x = 0;
for (int i = 0; i <= 127; i++)
{
int x = i;
char y = (char) x;
cout << y;
}
return 0;
}
Or should I put the cout outside with 16 separate lines? I am trying to print 17 ASCIIs starting from 1 in a row.
Use another variable that counts up along with i. When it reaches 16, reset it and print a new line. Repeat until the loop terminates.
i.e.(I may be off by one here, I didn't think about it too deeply)
for (int i=0, j=1; i<=127; i++,j++)
{
int x = i;
char y = (char) x;
cout << y;
if (j == 16) {
j = 0;
cout << '\n';
}
}
Alternatively, you could just check if (i % 16 == 0)
You don't need another variable to track it. i is already an int.
so if i modulo 16 equals 0 then print a newline
else print (char)i
EDIT:
Note, using variables like i is ok for simple iteration but its always good practice to name them better.
So think about how changing i to ascii in your program improves the readability. It instantly makes it even more clear what is it that you are trying to do here.
int main()
{
int charsThisLine =0;
for (int currentChar=0; currentChar<128; currentChar++)
{
if(charsThisLine==16)
{
cout<<endl;
charsThisLine = 0;
}
else
{
cout<<(char)currentChar;
charsThisLine++;
}
}
}
How about:
#include <iostream>
int main()
{
for(int i = 0, j = 0; i < 128; ++i, ++j)
{
if(j == 16)
{
j = 0;
std::cout << std::endl;
}
std::cout << static_cast<char>(i);
}
return 0;
}
Every iteration, j increases by 1; after 16 iterations, j is reset to 0, and a newline is printed.
Alternatively, as #Sujoy points out, you could use:
if((i % 16) == 0)
std::cout << std::endl;
But this introduces the problem of printing an extra newline character at the beginning of the output.
Yes, you need a second loop inside the first. (I misunderstood what is being requested.)
You also need to clean up the code. The first x is unused; the second x isn't needed since you could perfectly well use char y = (char)i; (and the cast is optional). You should normally use a loop for (int i = 0; i < 128; i++) with a < condition rather than <=.
You will also need to generate a newline somewhere (cout << endl; or cout << '\n';). Will you be needing to deal with control characters such as '\n' and '\f'?
Finally, I'm not sure that 'asciis' is a term I've seen before; the normal term would be 'ASCII characters'.