whats the smartest way to do something only once per iteration in a nested loop? i can't pull out the invariant part because the outer loop is very complex.
Here is my C++ example:
void foo::bar() {
if(oldCycle == tree.cycle) {
doSomething();
oldCycle++;
}
}
this method is called very often until tree.cycle is incremented. oldCycle is a private member variable of foo
claas foo {
public: ...
private:
int oldCycle;
};
Does the compiler optimize this code or will the if check run every iteration?
Edit: Here like requested the code with the loops:
the first loop is in the mexFunction() method, the algorithm is started in matlab and calls the mexFunction.
void mexFunction(...) {
for( tree.cycle = 0; tree.cycle<maxIt; tree.cycle++ ) {
foo->startfoo();
}
}
and here is the other loop:
void foo::startfoo() {
for(tree.cur_it = 0; tree.cur_it <=39; tree.cur_it++ ) {
bar();
}
}
For a general condition, you can't really optimize this out, since you would need to remove the special case from the collection one way or another.
However, for the special case of treating the first element specially (e.g. when printing a range with delimiters as "1, 2, 3"), you can use Knuth's "loop-and-a-half":
Naive loop:
for (unsigned int i = 0; i != values.size(); ++i)
{
if (i != 0) { std::cout << ", "; }
std::cout << values[i];
}
Loop-and-a-half:
if (!values.empty())
{
for (unsigned int i = 0; ; )
{
std::cout << values[i];
++i;
if (i == values.size()) { break; }
std::cout << ", ";
}
}
The latter construction is more involved, but saves you the mostly false check i != 0.
That said, it's quite plausible that a good compiler will do the partial unrolling even if you write the code the naive way.
For simple cases I prefer this method.
if ( ! values.empty())
{
std::cout << values[0];
for (size_t z = 1; z < values.size(); z++)
{
std::cout << ", " << values[z];
}
}
Related
I have a problem running my small piece of code.
I have a vector who reads in temperature from User Input. I want to process the data a bit. Giving out which kind of day it was (hot day, summer day, etc...) and which day was the hottest.
But everytime I want to get the maximum temperature with the function maxNumber I get 2 errors which I dont understand:
non-standard syntax; use '&' to create a pointer to member
"! =": Function overload cannot be resolved
Please help! Thx very much
Code:
#include <iostream>
#include <vector>
std::string klimaTag(float a) {
if (a >= 25 and a < 30) {
return "Sommertag";
}
else if (a >= 30 and a < 35) {
return "Heißer Tag";
}
else if (a >= 35) {
return "Wüstentag";
}
else {
return "Normaltag";
}
}
float maxNumber(std::vector<float> &a) {
float current_max = 0;
for (int i = a.begin; i != a.end; i++) {
if (a.at(i) > current_max) {
current_max = a.at(i);
}
return current_max;
}
}
int main()
{
std::vector<float> temperatures;
float current_temp;
for (int i = 0; i < 5; i++) {
std::cout << "Hoechsttemp für Tag " << i << " eingeben: ";
std::cin >> current_temp;
temperatures.push_back(current_temp);
}
for (int i = 0; i < 5; i++) {
std::cout << "Tag " << i + 1 << " ist ein " << klimaTag(temperatures.at(i)) << std::endl;
}
std::cout << maxNumber(temperatures);
}
First of all begin() and end() are method, so you're getting that error because you're trying to reference a function so it should require an address operator.
Second is begin() and end() return an iterator and not an index, and you're clearing trying to access like index.
Third thing is you're always returning after the first cycle as your return is inside it and should be outside.
To loop correctly your array is enough to use the for range loop
float maxNumber(std::vector<float> &a) {
float current_max = 0;
for(const auto& element : a) {
if(element > current_max){
current_max = element;
}
}
return current_max;
}
if you want to use the old way you can always do
float maxNumber(std::vector<float> &a) {
float current_max = 0;
for(int i=0; i<a.size(); ++a) {
if(a.at(i) > current_max){
current_max = a.at(i);
}
}
return current_max;
}
a.end refers to the function address, you need to invoke the function itself with a.end() hence the complaint about the non standard syntax, as if you meant to take the function address you could call &a.end. Same with a.begin.
To use the for loop as you described, you need int i = 0; i < a.size(). Moreover the return statement is inside the for loop in maxNumber. That's not what you want (it exits at the first loop cycle), put it outside.
Begin and end are actually methods for working with iterators. To use them you should change a bit the loop.
begin and end are functions which need to be called like functions: begin() and end().
However, you can use range-based for loop like:
float maxNumber(std::vector<float> &a) {
float current_max = 0;
for (auto const i : a) {
if (i > current_max) {
current_max = i;
}
}
return current_max;
}
Please, note where I put your return statement. It is outside of the for loop.
I am trying to improve my programming skills by solving couple of Code Jam questions. I have been stuck for a while on the "Trouble Sort" question from the Qualifier Rounds in 2018. My code produces the expected output with the example input in my console, but the online judge return "Wrong Answer".
Apparently Trouble sort is just like bubble sort, except instead of comparing the ith and i+1th elements, it compares the ith and i+2th elements and if the former is greater than the latter then the elements are swapped. The question says that this algorithm is flawed as arrays like 897 after trouble sort will return 798, which isn't sorted either. The task is to check if for a given list of integers, trouble sort is able to successfully sort the array or if it isn't then which is the index value of the first element that is out of place.
My code inputs the number of tests t and the size of integer list. Then I make a copy of it and put one copy through bubble sort and the other through trouble sort. Then I compare them element wise and if an index which has the two elements as different integers is found, it is outputted. I'm not sure what I am doing wrong here.
#include<iostream>
#include<vector>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
void swapVal(int& a, int& b)
{
int t = a;
a = b;
b = t;
}
int main()
{
int t;
cin >> t;
for (int i = 1; i <= t; i++)
{
int n;
cin >> n;
vector<int> bs(n);
vector<int> ts(n);
for (int i = 0; i < n; i++)
{
cin >> bs[i];
ts[i] = bs[i];
}
//bubbleSort(bs, n);
{
bool bsSorted = false;
while (!bsSorted)
{
bsSorted = true;
for (int i = 0; i < n - 1; i++)
{
if (bs[i] > bs[i + 1])
{
swapVal(bs[i], bs[i + 1]);
bsSorted = false;
}
}
}
}
//troubleSort(ts, n);
{
bool tsSorted = false;
while (!tsSorted)
{
tsSorted = true;
for (int i = 0; i < n - 2; i++)
{
if (ts[i] > ts[i + 2])
{
swapVal(ts[i], ts[i + 2]);
tsSorted = false;
}
}
}
}
bool same = true;
int minidx = 0;
for (int i = 0; i < n; i++)
{
if (bs[i] != ts[i])
{
same = false;
minidx = i;
break;
}
}
if (same == true)
{
cout << "Case #" << i << ": OK" << endl;
}
else if (same == false)
{
cout << "Case #" << i << ": " << minidx;
}
}
}
I am expecting the judge to give me a tick of approval, but instead it is repeatedly returning "Wrong Answer". What am I doing wrong here?
The algorithm looks correct to me. I noticed that in the false case you seem to be missing the newline. So two consecutive false statements will be on the same line.
cout << "Case #" << i << ": " << minidx<<'\n';
Might solve your problem.
Few remarks:
if (same == true) is equivalent to if(same) and if (same == false) to if(!same).
There's already std::swap.
Some people might not like nested for loops having equally named variables - the nested variable will hide the outer one.
I am creating a program that rewrites an array with values from a file. I have linked the code below. When running the file I get the error "Run-time check failure, stack around 'arr' variable was corrupted.
Also, the output of the program returns all the array locations with the same number,
arr[0] = -858993460
The numbers in the file, separated by a line are:
12
13
15
#include<iostream>;
#include<fstream>;
using namespace std;
template <class T>
void init(T * a, int size, T v)//done
{
for (int i = 0; i < size; i++)
{
a[size] = v;
}
}
bool getNumbers(char * file, int * a, int & size)//not done
{
int count = 0;
ifstream f(file);
while (f.good() == true && count < 1)
{
f >> a[count];
count++;
}
if (size > count)
{
return true;
}
else if (size < count)
{
return false;
}
}
void testGetNumbers()
{
int arr[5];
int size = 5;
cout << "Testing init and getNumbers." << endl;
init(arr, 5, -1);
cout << "Before getNumbers: " << endl;
for (int i = 0; i < size; i++)
{
cout << "arr[" << i << "] = " << arr[i] << endl;
}
if (getNumbers("nums.txt", arr, size))
{
cout << size << " numbers read from file" << endl;
}
else
{
cout << "Array not large enough" << endl;
}
cout << "After getNumbers: " << endl;
for (int i = 0; i < size; i++)
{
cout << "arr[" << i << "] = " << arr[i] << endl;
}
cout << endl;
}
int main()
{
testGetNumbers();
return 0;
}
This line in the first loop looks like having error.
a[size] = v;
It causes out of array bound access and memory/stack corruption. It should be
a[i] = v;
Starting with the main function, the line
return 0;
... is not necessary because that's the default return value for main. I would remove it, some people insist on having it, I think most people don't care. But it's always a good idea to be fully aware of what the code expresses, implicitly or explicitly, so: returning 0 expresses that the program succeeded.
For an explicit main return value I recommend using the names EXIT_SUCCESS and EXIT_FAILURE from the <stdlib.h> header.
Then it's much more clear.
main calls testGetNumbers, which, except for an output statement, starts like this:
int arr[5];
int size = 5;
init(arr, 5, -1);
As it happens the init function is has Undefined Behavior and doesn't fill the array with -1 values as intended, but disregard. For now, look only at the verbosity above. Consider writing this instead:
vector<int> arr( 5, -1 );
Using std::vector from the <vector> header.
Following the call chain down into init, one finds
a[size] = v;
That attempts to assign value v to the item just beyond the end of the array.
That has Undefined Behavior.
Should probably be
a[i] = v;
But as noted, this whole function is redundant when you use std::vector, as you should unless strictly forbidden by your teacher.
Back up in testGetNumbers it proceeds to call getNumbers, in that function we find
ifstream f(file);
while (f.good() == true && count < 1)
{
f >> a[count];
count++;
}
Generally one should never use f.good() or f.eof() in a loop condition: use f.fail(). Also, ~never compare a boolean to true or false, just use it directly. Then the loop can look like this:
ifstream f(file);
while (!f.fail() && count < 1)
{
f >> a[count];
count++;
}
Tip: in standard C++ you can write ! as not and && as and. With the Visual C++ compiler you have to include the <iso646.h> header to do that.
Disclaimer: the fixes noted here do not guarantee that the loop is correct for your intended purpose. Indeed the increment of count also when the input operation fails, looks probably unintended. Ditto for the loop limit.
The function continues (or rather, ends) with
if (size > count)
{
return true;
}
else if (size < count)
{
return false;
}
This has a big problem: what if size == count? Then the execution continues to fall off the end of the function without returning a value. This is again Undefined Behavior.
I leave it to you to decide what you want the function to return in that case, and ensure that it does that.
In your init function...
template <class T>
void init(T * a, int size, T v)//done
{
for (int i = 0; i < size; i++)
{
a[size] = v;
}
}
Nope:
a[size] = v;
Yup:
a[i] = v;
In an array, how do I check if any two variables are equal in something like
total_milk[7] = { b_milk, e_milk, d_milk, g_milk, a_milk, m_milk, h_milk };
without using casework
Iterate over the elements in the array, adding each element to an unordered_set.
The return value from unordered_set::insert() will tell you whether the element already was in the set.
Use two for loops and compare each element with other elements:
bool anyTwo(total_milk a[], std::size_t n) {
for (std::size_t i = 0; i < n - 1; i++) {
for (std::size_t j = i + 1; j < n; j++) {
if (a[i] == a[j]) {
return true;
}
}
}
return false;
}
This assumes your overloaded the == operator in your class. The second for loop counter j starts from i + 1 instead of 0 or i as there is no need to compare the already compared values or compare the element with itself.
The naive approach, which is fine for small data sets, is to simply use a comparison loop where each element is compared with every other element following it - there's no point comparing with those at or before an element since either the comparison has already been done or you will be comparing an item with itself.
The following complete program illustrates this approach:
#include <iostream>
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
for (size_t one = 0; one < sizeof(milk) / sizeof(*milk) - 1; ++one) {
for (size_t two = first + 1; two < sizeof(milk) / sizeof(*milk); ++two) {
if (milk[one] == milk[two]) {
std::cout << "Duplicate item: " << milk[one] << '\n';
return 1;
}
}
}
std::cout << "No duplicates\n";
}
For larger data sets, you can turn to the more optimised collections provided by the C++ library, such as the sets. A set is able to hold one of each value and has the useful property that it will return the fact that you tried to insert a duplicate, by returning both an iterator to the inserted/original item and a boolean value indicating whether it was new or a duplicate.
Like the earlier program, this one shows how you can use this method:
#include <iostream>
#include <unordered_set>
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
std::unordered_set<int> checkSet;
for (auto val: milk) {
auto iterAndBool = checkSet.insert(val);
if (! iterAndBool.second) {
std::cout << "Duplicate item: " << val << '\n';
return 1;
}
}
std::cout << "No duplicates\n";
}
A substantial improvement could be made to that using templates. This would allow it to handle arrays of any data type (assuming it has equality operators, of course) without have to code up specialisations for each. The code for that would be along the following lines:
#include <iostream>
#include <unordered_set>
template<class T> T *CheckDupes(T *collection, size_t count) {
std::unordered_set<T> checkSet;
for (size_t idx = 0; idx < count; ++idx) {
auto iterAndBool = checkSet.insert(collection[idx]);
if (! iterAndBool.second) {
return &(collection[idx]);
}
}
return nullptr;
}
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
int *dupe;
if ((dupe = CheckDupes<int>(milk, sizeof(milk) / sizeof(*milk))) != nullptr) {
std::cout << "Duplicate item: " << *dupe << '\n';
return 1;
}
std::cout << "No duplicates\n";
}
The templated function above will either return nullptr (if there are no duplicates) or the address of one of the duplicates. It's a simple matter to check that return value and act appropriately.
I suspect further improvement could be made to handle other collection types (not just naked arrays) but I'll leave that as an exercise for when you've mastered simpler templates :-)
Lets say I have a loop and an if statement in the loop. If i is true in the loop it prints with a space or comma and it does this for the rest of the i's that are true, but I want to do something else with the last i that that is true. How would I do this?
for (i = 0; i <= somenum; i++){
if (i % 2 != 0)
{
cout << i;
}
}
I want to figure out the last value that follows the condition and do something else with it.
There are really three ways to approach this problem. To illustrate this I'm going to use the example that you want to have a for loop print the numbers 0-9 separated by comas and spaces.
(1) Make the loop do the same thing every time, but modify your result after the loop. An example of how to do this is:
#include <iostream>
#include <sstream>
int main(int, char**) {
std::stringstream ss;
for (int i = 0; i < 10; ++i) {
ss << i << ", ";
}
ss.seekp(-2, std::ios_base::end);
ss << '\0';
std::cout << ss.str();
}
(2) Exit your loop before your last iteration and handle the last case outside the loop:
#include <iostream>
int main(int, char**) {
for (int i = 0; i < 9; ++i) {
std::cout << i << ", ";
}
std::cout << 9;
}
(3) Special case your last iteration in the loop. This option is bad, and you probably only want to do this in cases where you can't make 1 or 2 apply. The reason this is bad is because your conditional in the loop will be executed every time, and it will only be true once.
#include <iostream>
int main(int, char**) {
std::stringstream ss;
for (int i = 0; i < 10; ++i) {
if (i == 9) {
std::cout << i;
break;
}
std::cout << i << ", ";
}
}
In most cases option 2 is your best bet from a performance standpoint, but sometimes option 1 provides cleaner code which can be valuable.
If you have a "sequence" then you have no way of knowing if an element is the last or not. If you're using a for loop with a known length then it's trivial:
for(size_t i = 0; i < length; i++ ) {
if( i == length - 1 ) {
// do something for the last element
}
}
Reading your question, it sounds like you want to print a comma between elements but obviously don't want a trailing comma. The solution is not to test on the last, but to actually test on the first, like so:
bool isFirst = true;
iterator it;
for( it = sequence.begin(); it != sequence.end(); it++ ) {
if( !isFirst ) print(", ");
isFirst = false;
print( element );
}