I am writing a code to analyze a game, and I have a problem.
This code goes through every combination of 7 six-sided dices (from 1111111 to 6666666) and for every combination it sees if the combination makes some points or not. So I tried to check if it could put in the console every dice-combinations and the points associated just to check and it ran fine until 1223353 but at 1223354 it "crashed", as the image shows.Here we can see the console running my code.
So I don't understand why it just stops after ~10'000 iterations.
P.S.: I tried to run it in code blocks and it didn't work either...
Thank you for your answers!
Ok, when the debugger gets to this line it crashes:
if (sptopt[k]==sptopt[j]){ // here k == 3 and sptopt.size() == 3
sptopt.erase(sptopt.begin()+k); // this line crashes
sdesopt.erase(sdesopt.begin()+k);
soptch.erase(soptch.begin()+k);
}
I have looked at the state of the variables at the time of the crash and indeed:
k == 3 and
sptopt.size() == 3
Basically you are looping and erasing from a vector (which is very very inefficient from a memory perspective), and not checking that value of k is not equal/higher than the size of your vectors.
This is the stack I got:
Thread 1Queue : com.apple.main-thread (serial)
#0 0x00007fff95687f49 in _platform_memmove$VARIANT$Haswell ()
#1 0x000000010001b8ab in std::__1::enable_if<(is_same<std::__1::remove_const<int>::type, int>::value) && (is_trivially_copy_assignable<int>::value), int*>::type std::__1::__move<int, int>(int*, int*, int*) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:1904
#2 0x000000010001b856 in int* std::__1::move<int*, int*>(int*, int*, int*) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:1913
#3 0x000000010001b802 in std::__1::vector<int, std::__1::allocator<int> >::erase(std::__1::__wrap_iter<int const*>) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:1676
#4 0x000000010001b675 in main at /Users/**/Documents/iosapps/Chat App/newdaf/newdaf/main.cpp:604
Every time you are about to access a vector that changed in size in a loop, you must add checks such as:
if ( ( k < sptopt.size() ) && ( j < sptopt.size()) &&
( k < sdesopt.size() ) && ( j < sdesopt.size()) &&
( k < soptch.size() ) && ( j < soptch.size()) ...
Otherwise you access/erase an element that does not exist. In the case of deletion you get a runtime error. When accessing only, C++ may not be so kind as telling you that you are not where you thought you were (it did enter the function with k being an invalid index), and your program from then on behaves very strangely.
So you need to look at your functions and make sure your variables never go over the dimensions of the vectors you are using.
Related
I have been programming for a long time and stumbled across something very weird.
Somewhere in my code I had the following code:
for(int i = 0; i < 512; i++){
if((i * 12391823) % 5 == 1){
std::cout << i << std::endl;
}
}
I have already tracked the problem down to this piece of code.
I am using CLion. When compiling a Debug build, the loop is not endless and finishes eventually after printing a few numbers.
Yet when building as Release, it seems to never exit the loop.
...
>>> 15968768
>>> 15968773
>>> 15968778
...
If (i * 12391823) is replaced with a different (smaller) number, this does not happen.
E.g. with (i * 123), it does exit nicely:
...
>>> 482
>>> 487
>>> 492
...
I have also looked at the compile output which displayed the following:
warning: iteration 174 invokes undefined behavior [-Waggressive-loop-optimizations]
16 | if((i * 12391823) % 5 == 1){
| ~~~^~~~~~~~~~~
I do wonder why this would lead to the loop not ending.
It seems to overflow, yet it is not supposed to change i and therefor end the loop at some point, right?
I am very happy for an explanation on this topic!
Greetings
FInn
I do wonder why this would lead to the loop not ending. It seems to overflow, yet it is not supposed to change i and therefor end the loop at some point, right?
The answer is "Undefined Behaviour is undefined". It can do anything. But, the fact that you get a warning from aggressive-loop-optimizations may hint at the reason why loop becomes endless. It is possible that compiler decides to modify your loop into
for(int i = 0; i < 512 * 12391823; i + 12391823){
if(i % 5 == 1){
std::cout << i << std::endl;
}
}
Or maybe even
for(int i = 24783646; i < 512 * 12391823; i + 12391823 * 5){
std::cout << i << std::endl;
}
Both options could act strangely when integer overflow happens.
The solution is to not get into Undefined Behaviour lands. You can do that for example by changing type of i from int to unsigned long long
for(unsigned long long i = 0; i < 512; i++)
You are hitting undefined behavior in the line:
if((i * 12391823) % 5 == 1){
This is because for i larger then 173 the multiplication result exceeds integer range.
When it comes to undefined behavior - you are at the liberty of the compiler. In optimized builds they tend to compile away some (even large) chunks of code in and around the expression which causes it. And as you just experienced - it may even spread to the code which by itself is correct (the exit condition in the for loop).
BTW integer overflow (as far as I know) causes undefined behavior only for signed integers, it is well defined for unsigned types (the result is truncated). You may want o try i of unsigned type (but this still MAY yield results which you didn't expect).
As explained in the comments, the values generated in the loop, specifically this sub-expression:
(i * 12391823)
overflows for larger values of i. This results in undefined behaviour.
The issue is resolved by using a wider type for i, like long long.
Note: If you use an unsigned type, they will wrap around rather than overflow, if their max limit is exceeded.
I'm new to OpenMP, but am trying to use it to accelerate some operations on entries of a 2D array with a large number of rows and a small number of columns. At the same time, I am using a reduction to calculate the sum of all the array values in each column. The code looks something like this (I will explain the weird bits in a moment):
template <unsigned int NColumns>
void Function(int n_rows, double** X, double* Y)
{
#pragma omp parallel for reduction(+:Y[:NColumns])
for (int r = 0; r < n_rows; ++r)
{
for (int c = 0; c < NColumns; ++c)
{
X[r][c] = some_complicated_stuff(X[r], X[r][c]);
Y[c] += X[r][c];
}
}
}
To clarify, X is a n_rows x NColumns-sized 2D array allocated on the heap, and Y is a NColumns-sized 1D array. some_complicated_stuff isn't actually implemented as a separate function, but what I do to X[r][c] in that line only depends on X[r][c] and other values in the 1D array X[r].
The reason that NColumns is passed in as a template parameter rather than as a regular argument (like n_rows) is that when NColumns is known at compile-time, the compiler can more aggressively optimise the inner loop in the above function. I know that NColumns is going to be one of a small number of values when the program runs, so later on I have something like this code:
cin >> n_cols;
double** X;
double Y[n_cols];
// initialise X and Y, etc. . .
for (int i = 0; i < n_iterations; ++i)
{
switch (n_cols)
{
case 2: Function< 2>(X, Y); break;
case 10: Function<10>(X, Y); break;
case 60: Function<60>(X, Y); break;
default: throw "Unsupported n_cols."; break;
}
// . . .
Report(i, Y); // see GDB output below
}
Through testing, I have found that having this NColumns "argument" to Update as a template parameter rather than a normal function parameter actually makes for an appreciable performance increase. However, I have also found that, once in a blue moon (say, about every 10^7 calls to Function), the program hangsāand even worse, that its behaviour sometimes changes from one run of the program to the next. This happens rarely enough that I have been having a lot of trouble isolating the bug, but I'm now wondering whether it's because I am using this NColumns template parameter in my OpenMP reduction.
I note that a similar StackOverflow question asks about using template types in reductions, which apparently causes unspecified behaviour - the OpenMP 3.0 spec says
If a variable referenced in a data-sharing attribute clause has a type
derived from a template, and there are no other references to that
variable in the program, then any behavior related to that variable is
unspecified.
In this case, it's not a template type per se that is being used, but I'm sort of in the same ballpark. Have I messed up here, or is the bug more likely to be in some other part of the code?
I am using GCC 6.3.0.
If it is more helpful, here's the real code from inside Function. X is actually a flattened 2D array; ww and min_x are defined elsewhere:
#pragma omp parallel for reduction(+:Y[:NColumns])
for (int i = 0; i < NColumns * n_rows; i += NColumns)
{
double total = 0;
for (int c = 0; c < NColumns; ++c)
if (X[i + c] > 0)
total += X[i + c] *= ww[c];
if (total > 0)
for (int c = 0; c < NColumns; ++c)
if (X[i + c] > 0)
Y[c] += X[i + c] = (X[i + c] < min_x * total ? 0 : X[i + c] / total);
}
Just to thicken the plot a bit, I attached gdb to a running process of the program which hanged, and here's what the backtrace shows me:
#0 0x00007fff8f62a136 in __psynch_cvwait () from /usr/lib/system/libsystem_kernel.dylib
#1 0x00007fff8e65b560 in _pthread_cond_wait () from /usr/lib/system/libsystem_pthread.dylib
#2 0x000000010a4caafb in omp_get_num_procs () from /opt/local/lib/libgcc/libgomp.1.dylib
#3 0x000000010a4cad05 in omp_get_num_procs () from /opt/local/lib/libgcc/libgomp.1.dylib
#4 0x000000010a4ca2a7 in omp_in_final () from /opt/local/lib/libgcc/libgomp.1.dylib
#5 0x000000010a31b4e9 in Report(int, double*) ()
#6 0x3030303030323100 in ?? ()
[snipped traces 7-129, which are all ?? ()]
#130 0x0000000000000000 in ?? ()
Report() is a function that gets called inside the program's main loop but not within Function() (I've added it to the middle code snippet above), and Report() does not contain any OpenMP pragmas. Does this illuminate what's happening at all?
Note that the executable changed between when the process started running and when I attached GDB to it, which required referring to the new (changed) executable. So that could mean that the symbol table is messed up.
I have managed to partly work this out.
One of the problems was with the program behaving nondeterministically. This is just because (1) OpenMP performs reductions in thread-completion order, which is non-deterministic, and (2) floating-point addition is non-associative. I assumed that the reductions would be performed in thread-number order, but this is not the case. So any OpenMP for construct that reduces using floating-point operations will be potentially non-deterministic even if the number of threads is the same from one run to the next, so long as the number of threads is greater than 2. Some relevant StackOverflow questions on this matter are here and here.
The other problem was that the program occasionally hangs. I have not been able to resolve this issue. Running gdb on the hung process always yields __psynch_cvwait () at the top of the stack trace. It hangs around every 10^8 executions of the parallelised for loop.
Hope this helps a little.
I was working on a competitive programming question. I wrote this question to count the number of "VK" substrings.
int count(string test) {
int answer = 0;
for (int i = 0; i <= test.size()-2; i++) {
if (test.substr(i,2) == "VK")
answer++;
}
return answer;
}
Why did I receive this error message when I try just "V" as the argument?
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr: __pos (which is 2) > this->size() (which is 1)
Shouldn't the statements in the for loop not execute because the loop's condition failed?
Shouldn't the statements in the for loop not execute because the loop's condition failed?
Yes, you are right, but the condition didn't fail!. test.size() is a std::size_t, an implementation defined unsigned type.
The key here is that it is unsigned, meaning that it can overflow without invoking undefined behavior. When you pass "V", test.size() is 1. Then, 1 - 2 is equal to -1, but this overflows as an unsigned number cannot take negative numbers! The result is a very large number.
So, the loop executes a lot more times than you would have thought, and that is were the std::out_of_range exception comes from: On the second iteration, you are already accessing index 1, which is out of range (as test has size 1).
You need to introduce a pre-condition check:
if (test.size() < 2)
return 0;
I'm using lldb to debug a C++ program which has the following code
// Brute force to inner points
for (int i = 0; i < y_strip.size(); i++) {
for (int j = i + 1; j < y_strip.size(); j++) {
// If the vertical distance between the points is greater
// than delta, break the loop
if (abs(y_strip[i].y - y_strip[j].y) > delta) {
break;
} else {
mid_min_distance = minimal_distance(y_strip[i], y_strip[j]);
mid_min = min(mid_min_distance, mid_min);
}
}
}
and I want to come up with a way of stopping the program if the difference between j and i is greater than 10. How can I do this?
Compiling the program with clang++ -Wall -g closest.cpp -o closest
(lldb) break set -p "If the vertical distance between" -c "abs(i - j) > 10"
will do the trick. The -c option here is the breakpoint condition; if that expression evaluates to true, the program will stop at the breakpoint, otherwise the program will keep running. Note that you are still stopping to check the condition every time round the two loops, and this condition runs a function, so if the code you are checking is going to get run a lot, evaluating the condition might get slow. In that case it might be worth rewriting the condition to something like:
i - j > 10 || j - i > 10
since a simple expression with no function calls can be emulated in the debugger w/o having to call code in the debugee to check the condition.
And if this is code that you can modify, and it is going to get called a whole lot so that stopping each time around the loop to check the condition would be a big performance hit, then you can just put the check in your code:
if (abs(i - j) > 10)
printf ("Set a breakpoint here.\n");
rebuild it, and then just do:
(lldb) break set -p "Set a breakpoint here"
Note, the -p breakpoint option sets a breakpoint on the line whose source matches the pattern given in the option argument. You can also use file & line breakpoints:
(lldb) break set -f closest.cpp -l <whatever>
I like the pattern one because it moves with the intended location as the code is edited and it means I don't have to count lines.
I am new to C++ and I am trying to achieve a backward for loop, I founded solutions which works very well but I want to know what my version is not correct and making an infinite loop.
Here is a working version that I founded (I don't understand how we can decrease i in the condition..) :
for (unsigned i = size ; i-- > 0 ; )
{
// do stuff with i
}
Here is a version I wrote which works but don't go down to 0 (this way seems more logical to me) :
for (unsigned i = size-1 ; i > 0 ; i--)
{
// do stuff with i
}
If I say for exemple n=10, I will get this if I print i in the loop :
9
8
7
6
5
4
3
2
1
And here is the version which for me is the more logical and should go down to zero but is providing an infinite loop.
for (unsigned i = size-1 ; i >= 0 ; i--)
{
// do stuff with i
}
Could someone explain to me why the last version isn't working and what is the best choice to make ?
An unsigned number is always >= 0. (When it reaches zero a further decrement sets it to std::numeric_limits<unsigned>::max())
So your final for loop is equivalent to
for (unsigned i = size-1 ; true ; i--)
which, of course, loops forever.
In your first loop, you have i-- > 0 as the stopping condition. When i is zero, i-- is an expression with value zero (so the loop halts), despite the fact that i is then set to std::numeric_limits<unsigned>::max(). Some folk like (me included; cue the downvotes) to write i-->0 and regard --> as the slide operator. See What is the "-->" operator in C++?
The statement i >= 0 is always true because i is unsigned which means that is never below zero. If you decrease the value while i is zero, there will occur a so-called underflow and it will have a very high number.
The first version certainly gets the job done, so I would stick to it.