Why does the answer print out twice? - c++

I made a program that returns the product abc where a,b,c are pythagorean triples and add up to 1000. The program does output the correct answer but does it twice. I was curious as to why this is so. After playing around with it a bit I found out that it prints out when a = 200 b = 375 c = 425. And once again when a = 375 b = 200 c = 425.
bool isPythagTriple(int a, int b, int c);
int main()
{
for(int a = 1; a < 1000; a++)
{
for(int b = 1; b < 1000; b++)
{
for(int c = 1; c < 1000; c++)
{
if( ((a+b+c)==1000) && isPythagTriple(a,b,c) )
{
cout << a*b*c << " ";
break;
}
}
}
}
return 0;
}
bool isPythagTriple(int a, int b, int c)
{
if( (a*a)+(b*b)-(c*c) == 0 )
return true;
else
return false;
}

Just for what it's worth, I'd write this function:
bool isPythagTriple(int a, int b, int c)
{
if( (a*a)+(b*b)-(c*c) == 0 )
return true;
else
return false;
}
More like this:
bool isPythagTriple(int a, int b, int c) {
return a*a+b*b==c*c;
}

Break, in this case, will only break out of the c loop, not the b and a ones.
A quick fix is to ensure you don't get repeats by starting each variable greater than or equal to the previous (so b is never less than a and c is never less than b).
In addition, you can actually get rid of the c loop altogether since there's only one value of c that is valid for a given a,b pair (unless a + b + c > 1000 in which case there are none). I would try something like:
for (int a = 1; a < 1000; a++) {
for (int b = a; b < 1000; b++) {
int c = 1000 - a - b;
if (c >= b) {
if (isPythagTriple (a,b,c)) {
cout << a << " " << b << " " << c << " " << a*b*c << std::endl;
}
}
}
}
The overall effect of that is to reduce the total loop count from a billion (short scale) to about half a million hence reducing it by about 99.95% - that should be a tiny bit faster :-)
And potentially making it faster with Jerry Coffin's suggestion as well (and an inline suggestion to the compiler), a full program:
#include <iostream>
inline bool isPythagTriple(int a, int b, int c) {
return a * a + b * b == c * c;
}
int main() {
for(int a = 1; a < 1000; a++) {
for(int b = a; b < 1000; b++) {
int c = 1000 - a - b;
if (c >= b) {
if (isPythagTriple(a,b,c)) {
std::cout << a << " " << b << " " << c << " "
<< a*b*c << std::endl;
}
}
}
}
return 0;
}
which takes 0.004 seconds on average (system + user) on my box, with the original taking about 2.772 seconds on average (ten samples each). Not that it really matters unless you're running it many, many times, of course.
The output of that code is, as expected:
200 375 425 31875000

This is how break and continue work - break only exits the inner-most loop. Read the discussion on this question for some alternatives to this.

The reason this happens is because you only break out of the inner loop (for c). The outer loops carry on running and re-enter the inner loop, meeting the conditions again. There are numerous values that add to 1000 and you are catching some of them - you have caught 2, as your print indicates. You could use "return" instead of break if you want only the first combination of values output.
As for the "code block" I am not sure what you mean.. You already seem to know to write functions. If what you mean is a scope block, then you simply enclose the code of concern in curly braces -> { }
E.g.
{
int i = 0;
i++;
}

To prevent multiple orderings of the solutions, make sure that c >= b >= a. You can do this by changing the lower bounds:
for(int a = 1; a < 1000; a++) {
for(int b = a; b < 1000; b++) {
for(int c = b; c < 1000; c++) {

Related

IF-nesting in c++

heyall, just going through some textbook examples for my introductory c++ course and I would really appreciate it if somebody could clarify why the following code produces an output of 51 (I would expect it to not produce any output whatsoever), many thanks!:
#include <iostream>
using namespace std;
int main()
{
constexpr int a{9};
constexpr int b{1};
constexpr int c{5};
if (a < b < c)
if (c > b > a)
if (a > c) cout << 91;
else cout << 19;
else
if (b < c) cout << 51;
else cout << 15;
else
if (b < a < c)
if (a < c) cout << 95;
else cout << 59;
else
if (b < c) cout << 57;
else cout << 75;
return 0;
}
It seems you expect this expression:
if (a < b < c)
to be true if a, b, and c are in increasing order. But what actually happens is the expression becomes:
if ((a < b) < c)
which is either:
if (0 < c)
// or
if (1 < c)
Either way, that's probably not what you want. In fact, there's no good reason to ever write the above expression.
If you want to check whether the variables are increasing, you need to write something like:
if (a < b && b < c)
In c++, comparisons like 'X<=Y<=Z' do not have their mathematical meaning without parentheses. So, in
if (a < b < c)
we are getting
a < b => 9 < 1 => 0
'0' means the condition is false, which with 'c' is returning
0 < 5 => 1
"1" being returned means that the if condition is True.
Similarly, you can check for the nested if-else loops.

Loop not faster despite looping through half as many iterations?

I wrote a program that searches for primes:
#include <iostream>
#include <fstream>
#include <chrono>
typedef std::chrono::high_resolution_clock Clock;
using namespace std;
int main() {
int p;
int x = 1;
int b;
int a[1000000];
bool n = false;
a[0] = 2;
a[1] = 3;
auto t1 = Clock::now();
ofstream outfile;
outfile.open("p.txt");
for (p = 3; p < 7500000; p = p + 2)
{
for (b = 0; b <= x && n == 0; b++)
{
if (p % a[b / 2] == 0)
{
n = true;
}
}
if (n == false)
{
cout << p << endl;
outfile << p << endl;
x++;
a[x] = p;
}
else
{
n = false;
}
}
auto t2 = Clock::now();
std::cout
<< std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count()
<< " nanoseconds" << std::endl;
outfile.close();
}
Initially for the loop increment I had p++, but I changed that to p=p+2 because all primes essentially are odd and even numbers don't need to be checked. Problem is when I benchmarked this, there was no difference in speed between the old and new code. So what is the bottleneck in the process, if checking all the numbers is no different than checking half? And is there a better way to approach this?
Your outer loop skips half the numbers. But your inner loop tests every number twice. So you give up all your gains.
If you don't see that your inner loop does everything twice, consider that a[b/2] is the same when b is 1 as it is when b is 0.
It's this line:
for(b=0; b<=x && n==0; b++)
Once n=true; executes, the b loop exits because of the && n==0 condition. This happens with the very first test: every even number is divisible by two, which is a[0]. So for even numbers (that you include if you use p++ instead of p=p+2) the inner loop is very quick, much quicker than for a typical odd number. This explains why including them makes so little difference.

How to find the second minimum number without using arrays or loops

I tried to write a program that receive from the user 5 integers and print the second minimum number.
Here is a sample of what I've tried:
#include <iostream>
using namespace std;
int main () {
int a,b,c,d,e;
cin>>a>>b>>c>>d>>e;
if (a>b && a<c && a<d && a<e)
cout<<a<<endl;
if (b>a && b<c && b<d && b<e)
cout<<b<<endl;
if (c>a && c<b && c<d && c<e)
cout<<c<<endl;
if (d>a && d<b && d<c && d<e)
cout <<d<<endl;
if (e>a && e<b && e<c && e<d)
cout <<e<<endl;
return 0;
}
When I enter 1 2 3 4 5 it prints the second minimum, but when I enter
5 4 3 2 1 Nothing will print on the screen. What am I doing wrong with this? Is there any other way to write my program?
The problem you have with your logic is that you do not enforce yourself to print only 1 item, and at least one item.
By using the 'else' part of the if/else syntax, you will ensure that only one branch can ever be hit. You can then follow this up with just an else at the end, as you know all other conditions are false.
Once you've done this, you'll see that you print the last value, (1) rather than the expected (4). This is because your logic regarding how to find the 2nd lowest is wrong. b>a is false for the case 5,4...
Note:
Every employed engineer, ever, would make this a loop in a std::vector / std::array, and I would suggest you point your teacher to this post because encouraging loops is a good thing rather than bad.
Something like
vector<int> data;
for (int i=0; i<5; ++i) {
int t;
cin >> t;
data.push_back(t);
}
std::nth_element(data.begin(), data.begin()+1, data.end(), std::greater<int>());
cout << data[1];
There are 120 possible permutations on 5 elements. Your code should output the correct number for all of them. So a fool-proof code would use 120 repetitions of a check, like the following:
if (a > b && b > c && c > d && d > e) // the order is a>b>c>d>e
cout << d;
else if (a > b && b > c && c > e && e > d) // the order is a>b>c>e>d
cout << e;
...
else if (e > d && d > c && c > a && e > b) // the order is e>d>c>a>b
cout << a;
else // the order is e>d>c>b>a
cout << b;
This is very long, inefficient and tricky code. If you do a typo in just one variable, it will output a wrong answer in some rare cases. Also, it doesn't handle the possibility of some inputs being equal.
If the number of inputs to a sorting algorithm is a known small constant, you can use an approach called sorting networks. This is a well-defined computer science problem, which has well-known optimal solutions for small numbers of inputs, and 5 certainly is small. An optimal sorting network for 5 inputs contains 9 comparators, and is described e.g. here.
Since you don't need to sort the numbers, but only to know the second smallest input, you can reduce the size of the network further, to 7 comparators.
The full sorting network (without the reduction from 9 to 7) translated to C++:
if (b < c)
swap(b, c);
if (d < e)
swap(d, e);
if (b < d)
swap(b, d);
if (a < c)
swap(a, c);
if (c < e)
swap(c, e);
if (a < d)
swap(a, d);
if (a < b)
swap(a, b);
if (c < d)
swap(c, d);
if (b < c)
swap(b, c);
// now the order is a ≥ b ≥ c ≥ d ≥ e
cout << d;
This code is also obscure - not obvious at all how and why it works - but at least it is small and in a sense optimal. Also, it's clear that it always prints something (so it fixes the original problem) and supports the case of partially equal inputs.
If you ever use such code in a larger project, you should document where you took it from, and test it. Fortunately, there are exactly 120 different possibilities (or 32, if you use the
zero-one principle), so there is a way to prove that this code has no bugs.
This should work for you. (Note that it might not be the best approach and you can minimize it with a function to calculate min and secondMin instead of the ugly copy paste of the logic but it will get you started:
#include <iostream>
using namespace std;
int main () {
int a,b,c,d,e;
int min, secondMin;
cin>>a>>b;
min = a < b ? a : b;
secondMin = a < b ? b : a;
cin>>c;
if (c < min)
{
secondMin = min;
min = c;
}
else if (c < secondMin)
{
secondMin = c;
}
cin>>d;
if (d < min)
{
secondMin = min;
min = d;
}
else if (c < secondMin)
{
secondMin = d;
}
cin>>e;
if (e < min)
{
secondMin = min;
min = e;
}
else if (e < secondMin)
{
secondMin = e;
}
cout << "min = " << min << ", secondMin = " << secondMin << endl;
return 0;
}
if you have any questions feel free to ask in the comment
#include <set>
std::set<int> values = { a, b, c, d, e }; // not an array.
int second_min = *std::next(values.begin(), 1); // not a loop
What about a recursive and more generic approach?
No arrays, no loops and not limited to just 5 integers.
The following function get_2nd_min() keeps track of the two lowest integers read from std::cin a total of count times:
#include <climits>
#include <cstddef>
#include <iostream>
int get_2nd_min(size_t count, int min = INT_MAX, int second_min = INT_MAX)
{
if (!count)
return second_min; // end of recursion
// read next value from cin
int value;
std::cin >> value;
// Does second_min need to be updated?
if (value < second_min) {
// Does min also need to be updated?
if (value < min) {
// new min found
second_min = min; // move the so far min to second_min
min = value; // update the new min
} else {
// value is lower than second_min but higher than min
second_min = value; // new second_min found, update it
}
}
// perform recursion
return get_2nd_min(count - 1, min, second_min);
}
In order to read 5 integers and obtain the 2nd lowest:
int second_min = get_2nd_min(5);
One approach is to first find the minimum number, min and then find the smallest value that isn't min. To do this first find the minimum value:
int min = std::min(a, std::min(b, std::min(c, std::min(d, e))));
Now we need to do the same again, but ignoring min. We can do this using a function called triMin which takes 3 values and discards any value that is the minimum:
int triMin(int currentMin, int left, int right)
{
if(currentMin == left) return right;
if(currentMin == right) return left;
return std::min(left, right);
}
You can now combine them to get the answer:
int a = 5, b = 4, c = 3, d = 2, e = 1;
int min = std::min(a, std::min(b, std::min(c, std::min(d, e))));
int min2 = triMin(min, a, triMin(min, b, triMin(min, c, triMin(min, d, e))));
std::cout << "Second min = " << min2 << std::endl;
This prints 2
This task can be fulfilled using one-pass algorithm. There is no need to use any collections (arrays, sets or anything).
This one-pass algorithm is memory efficient - it does not require storing all elements in collection (and wasting memory) and will work even with large number of elements when other solutions fail with out of memory.
General idea of this algorithm is like this:
take each number in order
you need two variables to store minimum and second minimum numbers from all already seen numbers.
when you get number you need to test it with current minumum to find if it is new minimum number.
if it is store it as minimum, store old minimum in second minimumnumber
otherwise check if it is less than second minimum number.
if it is store it as second minimum number.
now second minimum number contains answer for all already seen numbers.
repeat while there numbers that was not seen.
After investigating all numbers second minimum contain the answer.
Here is implementation with c++17 (link to wandbox):
#include <iostream>
#include <optional>
int main()
{
int a, b, c, d, e;
std::cin >> a >> b >> c >> d >> e;
// you can find second minimal number while going through each number once
auto find_current_answer = [minimum = std::optional<int>{}, next_to_minimum = std::optional<int>{}](int next) mutable {
// when receiving next number
// 1. check if it is new minimum
if (!minimum || minimum > next) {
// move values like this: next_to_minimum <- minimum <- next
next_to_minimum = std::exchange(minimum, next);
}
// 2. else check if it is new next_to_minimum
else if (!next_to_minimum || next_to_minimum > next) {
next_to_minimum = next;
}
// 3. return current answer
return next_to_minimum;
};
// repeat as much as you like
find_current_answer(a);
find_current_answer(b);
find_current_answer(c);
find_current_answer(d);
// store answer that is interesting to you
auto result = find_current_answer(e);
// if it has value - it is the answer
if (result) {
std::cout << "Answer: " << *result << '\n';
}
else {
std::cout << "Not enough numbers!\n";
}
}
Update
In this solution I'm using the min function:
#include <iostream>
using namespace std;
int minDifferentFromFirstMin(int x, int y, int firstMin) {
if(x < y) {
if(x != firstMin) {
return x;
}
else {
return y;
}
}
if(y < x) {
if(y != firstMin) {
return y;
}
else {
return x;
}
}
//if x & y are equals, return one of them
return x;
}
int main () {
int a,b,c,d,e;
int iter11, iter12, iter13;
int iter21, iter22, iter23;
int firstMinimum, secondMinimum;
cin>>a>>b>>c>>d>>e;
//iteration 1: find the first minimum
iter11 = min(a, b);
iter12 = min(c, d);
iter13 = min(iter11, iter12);
firstMinimum = min(iter13, e);
//iteration 2: find the second minimum
iter21 = minDifferentFromFirstMin(a, b, firstMinimum);
iter22 = minDifferentFromFirstMin(c, d, firstMinimum);
iter23 = minDifferentFromFirstMin(iter21, iter22, firstMinimum);
secondMinimum = minDifferentFromFirstMin(iter23, e, firstMinimum);
cout<<secondMinimum<<endl;
}

What is the purpose of the increment statement?

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;}

Is using goto a legitimate way to break out of two loops?

I am solving problem 9 on the Project Euler. In my solution I use a "goto" statement to break out of two for loops. The Problem is the following:
A Pythagorean triplet is a set of three natural numbers, a b c, for which,
a^2 + b^2 = c^2
For example, 3^2 + 4^2 = 9 + 16 = 25 = 52.
There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc.
My solution is in c++:
int a,b,c;
const int sum = 1000;
int result = -1;
for (a = 1; a<sum; a++){
for (b = 1; b < sum; b++){
c = sum-a-b;
if (a*a+b*b == c*c){
result = a*b*c;
goto found;
}
}
}
found:
std::cout << "a:" << a << std::endl;
std::cout << "b:" << b << std::endl;
std::cout << "c:" << c << std::endl;
std::cout <<"Result:" << result << std::endl;
Since "goto" statements are not very popular among c++ programmers, i would like to know, if this could be considered a reasonable use of "goto". Or if there is a better solution for the problem that doesn't need "goto". By that I don't mean a solution which just avoids "goto", but which avoids "goto" in a way that improves the algorithm.
return is a "structured" goto which many programmers find more acceptable! So:
static int findit(int sum, int* pa, int* pb, int* pc)
{
for (int a = 1; a<sum; a++) {
for (int b = 1; b < sum; b++) {
int c = sum-a-b;
if (a*a+b*b == c*c) {
*pa = a; *pb = b; *pc = c;
return a*b*c;
}
}
return -1;
}
int main() {
int a, b, c;
const int sum = 1000;
int result = findit(sum, &a, &b, &c);
if (result == -1) {
std::cout << "No result!" << std::endl;
return 1;
}
std::cout << "a:" << a << std::endl;
std::cout << "b:" << b << std::endl;
std::cout << "c:" << c << std::endl;
std::cout <<"Result:" << result << std::endl;
return 0;
}
In my opinion it's fine to use goto in a situation like this.
Btw, the condescending preaching against goto usually comes from people who just parrot what they heard others say or read somewhere..
See this question about breaking out of 2 loops. There are much better answers provided than using a goto.
The best answer provided is to place your second loop into a function, and call that function from inside your first loop.
code copied from mquander's response
public bool CheckWhatever(int whateverIndex)
{
for(int j = 0; j < height; j++)
{
if(whatever[whateverIndex][j]) return false;
}
return true;
}
public void DoubleLoop()
{
for(int i = 0; i < width; i++)
{
if(!CheckWhatever(i)) break;
}
}
Though I do feel that using a goto in this case isn't quite as bad as killing kittens. But it's close.
I can't think of a better alternative. But one alternative not using goto would be modifying the first for-loop:
for (a = 1; a<sum && result == -1; a++){
Then break out of the second for-loop. That will work assuming the result will never be -1 after the second for-loop has been broken by break.
You could declare a bool found = false at the top and then add && !found to your for loop conditionals (after a < sum and b < sum) and then set found to true where your current goto is. Then make your output conditional on found being true.
int a,b,c,sum = 1000;
for (a = 1; a<sum; ++a)
for (b = 1; b<sum; ++b){
c = sum-a-b;
if (a*a+b*b == c*c) sum = -a*b*c;
}
printf("a: %d\n",a-1);
printf("b: %d\n",b-1);
printf("c: %d\n",c);
printf("Result: %d\n",-sum);
Also optimized result out.. :P
Anyway i love gotos!