C++ link errors

Don’t get so defensive, booklover. I was asking merely because I’m a beginner programmer too and just wanted to make sure. BTW what C++ book do you use? I noticed that the one I use is pretty much completely useless to me (way too much info, most of which I probably wouldn’t use for a first cpp course). My lecture slides, however, are very concise. Let me know if you want a link.

qPoints = (y-50)/10;
if (qPoints == 5)
qPoints = 4;

Each if statement provides the opportunity to royally freak up your command pipeline (the processor may have to end up following the opposite path of the one it’s prepared for), and you should try to avoid them (heck, there should be a way to avoid the one I left in, I just can’t think of it right now). Plus, if the score is less than 60, then you set qPoints 5 different times your way, and memory accesses should also be minimized.
-LV

Actually, for a beginner programmer in C++, it’s not that bad. The primary issue was the passing of the parameter (and not using x as a global variable). Fix that, and the rest is fine. Granted, it’s not the most efficient way of doing it, although that can easily be improved with just an if … else if … else if … else pattern, reversing the order of the if conditions, to insure that the conditional checks are all mutually exclusive (i.e. so we don’t have to check ALL of them).

Of course, Lord Vor’s trick is also a good one, allowing for brevity of code and fewer operations – but not necessarily something I would expect a beginner to come up with, especially if they are just learning functions and program control for the first time.

*BTW what C++ book do you use? I noticed that the one I use is pretty much completely useless to me (way too much info, most of which I probably wouldn’t use for a first cpp course). *

What book is this, Ian Fan?

If your compiler represents true as 1 and false as 0, you can avoid the if statement by writing qPoints = (y - 50)/10 - ((y - 50)/10 == 5);. Unless I am sorely mistaken, this will work in MS Visual C++.

There’s a way to do it that isn’t compiler-dependent, but a lot of intermediate students wouldn’t come up with this.

(((y - 50)/10 == 5) && (qPoints = (y - 50)/10 - 1)) || (qPoints = (y - 50)/10);

This works because of the short-circuiting property of the logical operators in C++. If (y - 50)/10 isn’t 5, the other operand of the && won’t even be evaluated. If it is 5, the assignment statement will return 5, and the && will evaluate to true, so the other operand of the || won’t be evaluated.

However, unless you’re programming for a hard real-time system, you gotta be an asshole to do it that way. In most areas, code legibility is far more important than efficiency.

Personal opinion and ranting follows.

The short circuiting isn’t likely to be any better, at the compiler level, than the original:

qPoints = (y-50)/10;
if (qPoints == 5)
qPoints = 4;

Any modern compiler… actually, even a relatively feeble one… would turn this into a subtraction followed by a division (must be done in all cases), followed by a test, and if the test fails, to branch around the qPoints=4 direct assignment.

Worst case scenario is that you crash the instruction pipeline for your processor, which is an esoteric concern, and it would be difficult to avoid even if you cared. The number of instructions, in any case, to accomplish this is minimal, and contains only one branch.

Thing is, this:

(((y - 50)/10 == 5) && (qPoints = (y - 50)/10 - 1)) || (qPoints = (y - 50)/10);

doesn’t change the issue. For the short-circuiting to work, you still have a division, a subtraction, and a test. If the test fails, you branch to the (qPoints = (y - 50)/10) part. If it succeeds, you fall through to the (qPoints = (y - 50)/10 - 1) part, but then have to branch around the (qPoints = (y - 50)/10) part. In either case you’ve gained yourself one more division, and at least one more subtraction.

You could make a case for the compiler being truly superior and deciding that it can do something clever to let the processor evaluate parts of these expressions in parallel, thereby enabling you to gain more in terms of having the answers already solved regardless of which branch you take than you lose for the possibly extra math. Some processors do this kind of magic even in the code likely produced by LordVor’s case, though.

However, assuming that the short circuiting works in the simplest possible way, you’ve still gained nothing. There’s still at least a test and branch, and you’ve complicated your code while accomplishing next to nothing. If you’re really this worried about efficiency and something as esoteric as crashing your instruction pipeline, you probably don’t want to be writing that tiny fragment in C++ anyway. The compiler may not do things in the order or manner you expect from the written C++ source.

While it’s worth from time to time looking at the efficiency of different constructs in the language (like short circuiting), generally speaking for efficiency it’s best to go with simple and let today’s modern compilers take care of fiddly optimizations. I don’t often encounter a great deal of benefit, if any, for this kind of esoterica, and sometimes you actually defeat the compiler’s optimization schemes by overcomplicating your code.

(I’m ignoring, for the moment, efficiency gained from a more complicated algorithm that changes the big-O complexity of the solution).

Go with LordVor’s. Efficiency is unlikely to be relevant in a first year class, and it would be damned tough to make it more efficient anyway, especially at the cost of, er, cryptification. :slight_smile:

Er, in short, why make things more complicated for yourself? These concerns are for advanced high performance scenarios, and are in no way relevant or errors for a beginning C++ course.

Effiiciency may not be relevant, but it’s never too early to learn. I do think my routine, of the ones suggested, is the best combination of easy to read and most likely to be acceptibly fast.

Now, if I had a compiler/architecture that I knew would equate ‘1’ to true, I could replace the if with:

qPoints -= (qPoints >4);

But that would likely get you shot in a beginning programming class. I just wanted to show that I could come up with a way to avoid the if and not add another division or branch.

-lv

As it should. There really is no need to obfuscate your code like that - first, because your compiler should handle the optimizations; second, because in 99% of applications, you really don’t need those few extra clock cycles as much as you need code that someone else will be able to understand.

If optimization is so important that you would choose “qPoints -= (qPoints > 4)” over something at least as readable as “if (qPoints > 4) qPoints = 4”, you should be writing in assembler.

And if you’re using a modern compiler and targeting a modern Intel CPU, the latter code won’t branch anyway–it’ll use CMOV.

Bravo, Mr2001. Bravo.

Also, (on a CPU without conditional variations on instructions)

qPoints -= (qPoints > 4);

may just end up doing a comparison followed by a test again (to see if we’re subtracting 1), depending on the processor and how hard the compiler works.

So I have to agree with Mr2001. You’ve not necessarily managed to avoid a branch; and as Mr2001 points out, a modern compiler might render most of these cases very similar in performance because of compiler cleverness.