Unary arithmetic operators

There are two unary arithmetic operators, plus (+), and minus (-). As a reminder, unary operators are operators that only take one operand.

Operator | Symbol | Form | Operation |
---|---|---|---|

Unary plus | + | +x | Value of x |

Unary minus | - | -x | Negation of x |

The unary minus operator returns the operand multiplied by -1. In other words, if x = 5, -x is -5.

The unary plus operator returns the value of the operand. In other words, +5 is 5, and +x is x. Generally you won’t need to use this operator since it’s redundant. It was added largely to provide symmetry with the *unary minus* operator.

For best effect, both of these operators should be placed immediately preceding the operand (e.g. `-x`

, not `- x`

).

Do not confuse the *unary minus* operator with the *binary subtraction* operator, which uses the same symbol. For example, in the expression `x = 5 - -3;`

, the first minus is the *binary subtraction* operator, and the second is the *unary minus* operator.

Binary arithmetic operators

There are 5 binary arithmetic operators. Binary operators are operators that take a left and right operand.

Operator | Symbol | Form | Operation |
---|---|---|---|

Addition | + | x + y | x plus y |

Subtraction | - | x - y | x minus y |

Multiplication | * | x * y | x multiplied by y |

Division | / | x / y | x divided by y |

Modulus (Remainder) | % | x % y | The remainder of x divided by y |

The addition, subtraction, and multiplication operators work just like they do in real life, with no caveats.

Division and modulus (remainder) need some additional explanation. We’ll talk about division below, and modulus in the next lesson.

Integer and floating point division

It is easiest to think of the division operator as having two different “modes”.

If either (or both) of the operands are floating point values, the *division operator* performs floating point division. Floating point division returns a floating point value, and the fraction is kept. For example, `7.0 / 4 = 1.75`

, `7 / 4.0 = 1.75`

, and `7.0 / 4.0 = 1.75`

. As with all floating point arithmetic operations, rounding errors may occur.

If both of the operands are integers, the *division operator* performs integer division instead. Integer division drops any fractions and returns an integer value. For example, `7 / 4 = 1`

because the fractional portion of the result is dropped. Similarly, `-7 / 4 = -1`

because the fraction is dropped.

Warning

Prior to C++11, integer division with a negative operand could round up or down. Thus `-5 / 3`

could result in -1 or -2. This was fixed in C++11, which always drops the fraction (rounds towards 0).

Using static_cast<> to do floating point division with integers

The above raises the question -- if we have two integers, and want to divide them without losing the fraction, how would we do so?

In lesson 4.11 -- Chars, we showed how we could use the *static_cast<>* operator to convert a char into an integer so it would print as an integer rather than a character.

We can similarly use *static_cast<>* to convert an integer to a floating point number so that we can do *floating point division* instead of *integer division*. Consider the following code:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { int x{ 7 }; int y{ 4 }; std::cout << "int / int = " << x / y << '\n'; std::cout << "double / int = " << static_cast<double>(x) / y << '\n'; std::cout << "int / double = " << x / static_cast<double>(y) << '\n'; std::cout << "double / double = " << static_cast<double>(x) / static_cast<double>(y) << '\n'; return 0; } |

This produces the result:

int / int = 1 double / int = 1.75 int / double = 1.75 double / double = 1.75

The above illustrates that if either operand is a floating point number, the result will be floating point division, not integer division.

Dividing by zero

Trying to divide by 0 (or 0.0) will generally cause your program to crash, as the results are mathematically undefined!

1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> int main() { std::cout << "Enter a divisor: "; int x{}; std::cin >> x; std::cout << "12 / " << x << " = " << 12 / x << '\n'; return 0; } |

If you run the above program and enter 0, your program will either crash or terminate abnormally. Go ahead and try it, it won’t harm your computer.

Arithmetic assignment operators

Operator | Symbol | Form | Operation |
---|---|---|---|

Assignment | = | x = y | Assign value y to x |

Addition assignment | += | x += y | Add y to x |

Subtraction assignment | -= | x -= y | Subtract y from x |

Multiplication assignment | *= | x *= y | Multiply x by y |

Division assignment | /= | x /= y | Divide x by y |

Modulus assignment | %= | x %= y | Put the remainder of x / y in x |

Up to this point, when you’ve needed to add 4 to a variable, you’ve likely done the following:

1 |
x = x + 4; // add 4 to existing value of x |

This works, but it’s a little clunky, and takes two operators to execute (operator+, and operator=).

Because writing statements such as `x = x + 4`

is so common, C++ provides five arithmetic assignment operators for convenience. Instead of writing `x = x + 4`

, you can write `x += 4`

. Instead of `x = x * y`

, you can write `x *= y`

.

Thus, the above becomes:

1 |
x += 4; // add 4 to existing value of x |

5.3 -- Modulus and Exponentiation |

Index |

5.1 -- Operator precedence and associativity |

its good to know about arithmetic assignment operators

but wouldn't it be more readable to use the normal way ? is it safe if i make it my standard not to use the arithmetic assignment operators ?

like its easier to read x = x + 4 ; rather than x += 4;

because it leaves you with a few millisecond to think about what that += means and make sure you are not confusing it with another operator.

It may seem weird at first, but it's really easy to get used to it. You just need to think of it as "increase x by 4" not "set x to x + 4". It comes with practice

wanted to see if i can directly cast the result into a double

std::cout << static_cast<double> (7 / 4) ;

resulted in 1

#failed

It actually worked, but not as you expected.

What you did is to perform an integer division (with truncation) and then cast the integer result into a double.

thanks ...

can someone explain

will result divide or mod by zero error but

print inf

For me,

i) if 0 is stored in an int type variable, then 10/var results in floating point exception.

ii) sending 10/0 to the console results in gibberish (could be any value).

iii) if 0 is double type value (e.g. 0.0) then 10/0.0 results in inf.

It's just undefined behavior I guess. Why would I devide anything by 0 anyway :)

I think it's because 0.0 is a double, and doubles are somewhat weird. You can store NaN and PosInf and NegInf in doubles, and you can use scientific notation on them, so hence, I'm not surprised this works.

Here's what I mean:

guys please help me im new... can Add (+) or subtract (-) operators will be used to create the Multiplication and Division function while there is No Multiplication (*) and Division (/) operators must be used in the program? if so can you tell me how? thanks...

Yes, but it wouldn't make sense.

If you want to do 5 * 5 but with using '+' you can do it a following way.

Create for loop and inside it do 5 iteration of the following expression:

X=+5

the beauty of "x += 5" is that we don't have to write abherrations like "x = x + 5" :)

i actually prefer x = x + 5 as it is more detailed than x += 5

its faster for me to understand x = x + 5 even a non programmer can understand x = x + 5 means that x is now the value of x PLUS 5

but a newcomer such as myself or a non programmer will have a slight delay until we remember what += does.

Wow Nice

Nice! a good way of testing the pickedOperator instead of using nested else ifs would be a switch statement like this:

Would the result of your math be integer and disregard floating point number? I would use static_cast<> for division and modulus.

hey sheepy, how did you change the default avatar image?

1. Avoid "using namespace". It can cause naming conflicts. Prefix every occurrence of "cin" and "cout" with "std::" instead.

2. Function names should generally start with a verb that describes what the function does, e.g. "printNames()", "getPotatoes()" etc. The "intro()" function in this case should be called "printIntro()" instead.

3. The "intro()" function is actually redundant, since it's only executed once. It makes the code *longer*, not shorter.

4. Use single quotes for \n, since it's 1 character. "\n" in your program should be '\n'

Everything else looks good, well done!

this can't be used with direct initialization right?

This isn't initialization at all, so I'm not sure what you're getting at

Oh nvm XD I mixed up some concepts together

This is same as saying like this

x * y => x multiplied by y

Can we use "times" too? You didn't mention that, I thought maybe it is not a good way to use "times" instead of "multiplied"

x * y => x times y

What do you mean exactly? You aren't writing "times" in your code (aside from comments), so it shouldn't matter if you "use" either "times" or "multiplied" - they are synonyms.

I assume the authors chose "multiply" because it doesn't have other definitions besides "repeated addition", whereas "times" refers also to repetition in general (e.g. "doing it 3 times") or time (e.g. "at what times?").

"Trying to divide by 0 (or 0.0) will generally cause your program to crash, as the results are mathematically undefined!"

I just want to mention that my program crashes only when I try to divide an int by 0. And it seems to work when I divide an integer number by 0.0

or a double number by 0.

E.g. this code doesn't crash when x is 0:

Floating point numbers might support a special NaN (Not a Number) value which is used as the result of division by 0. That's implementation-defined, your code might crash or throw on another system.

Thanks for clarifying.

@nascardriver You mentioned that division by 0.0 might support a special NaN and it could crash in another system. But in chapter "4.8 — Floating point numbers" it says if we divide by 0.0 we get infinity and NaN if 0.0 is divided by 0.0.

I tried it on my system and online compiler, it throws an error on integer 0 but gives infinity on 0.0

So, is it safe to assume that it will always generate infinity or NaN, or it could throw error on another system

No. Division by 0.0 causes undefined behavior, unless your compiler supports it. Just because something works with compiler x, y, and z doesn't mean it's safe. Division by 0 should be avoided in any case. If, for whatever reason, you need to divide by 0, make sure that your compiler is using IEEE 754 floating pointer numbers. Only then is it guaranteed to be safe, in every other case, the division produces undefined behavior.

`static_assert` aborts compilation if the condition we give it is `false`.::is_iec559` is `true` if the compiler uses IEEE 754 for `double` values.

`std::numeric_limits

This way, if the compiler uses another format for `double`, the code won't compile at all. If the code compiles, the division is guaranteed to produce an inf value.

Hi.Found a minor issue with the code in the section "Using static_cast<> to do floating point division with integers". You've used double quotes instead of single quotes for newline feed. It should be '\n'.

Thanks a lot! As long as the lessons do it wrong, the readers will too.

Just a grammar point / typo: under "Using static_cast<> to do floating point division with integers" you say the above"begs the question" when I believe you mean it "raises the question." Not a big deal, but I thought I'd mention it since I am finding the course extremely helpful so far! Thanks for putting this all together!

This lesson is no longer begging for questions, thanks!

Did you mean to have the '5' in the sentence?

"Because writing statements such as x = x + 5 is so common, C++ provides 5 arithmetic assignment operators for convenience. Instead of writing x = x + 5, you can write x += 5. Instead of x = x * y, you can write x *= y."

It is confusing because "C++ provides 5 arithmetic assignment operators"

Does C++ provide five operators (if so, you have only shown two) or does C++ provide 5 with some operators?

Lesson amended. Thanks!

"Trying to divide by 0 (or 0.0) will generally cause your program to crash, as the results are mathematically undefined!"

I hate to be so pedantic, especially since I haven't studied math in 20 years but I always remembered division by zero as infinity. It was a long time ago so I had to check and Wolfram Alpha agrees.

https://www.wolframalpha.com/input/?i=divide%20by%200

I'd recommend that you strike the word mathematically or change it to arithmetically.

Infinity isn't a discrete number, and even if it were, would dividing by 0 produce positive or negative infinity? It's more correct to say it's undefined. See http://mathforum.org/library/drmath/view/53336.html

I had an issue when I tried to compile the divide by zero example stating this:

"C:\Users\Senith\Desktop\testing\testing\main.cpp|6|error: extended initializer lists only available with -std=c++11 or -std=gnu++11|"

and on ln6 was: int x{}; which i changed to int x; and it compiled with no errors. Any idea why i got that error on codeblocks?

You didn't enable a higher standard in code::block's settings.

Brace initialization and many other features aren't available in C++03 (Which is probably what you're using). In your project settings, enable the highest possible C++ standard.

Replying to Jon, posting Sep 28, 2019 at 1:04 AM.

Jon,

As a mathematician wannabe (majored in it) I am conditioned to be that pedantic. Dividing by zero is an undefined operation. To emphasize what Alex says, infinity is not a number at all. It is a concept. It took my first Real Analysis (aka advanced calculus) to rigorously define what is meant by "approaching infinity".

Here's a simple paradox:

If 1 / 0 == infinity then infinity * 0 must == 1.

But 2 / 0 also == infinity, so infinity * 0 must == 2.

Hmm... Then 1 == 2. EGAD! (Is there a Latin acronym in EGAD, like QED? :-)

The problem was that I was treating infinity like a number.

(Plugging myself as a Math tutor. :-)

Hi, Alex! If I can, I suggest you to order your operator table in their operator precedence in their related lesson, like your binary arithmetic operators table in this lesson (that is not ordered in their operator precedence although we know that we learn addition and substraction first then multiplication and division).

is the following func okay for last question

bool isEven(int x)

{

return (!(x % 2)) ;

}

You can do it and it's always going to work. But `(x % 2) == 0` is easier to read, since you don't have to thing about boolean conversions.

Hi Nascardriver & Alex

Quiz 2 - Ive tried to keep it as simple and small as possible. Any suggestions please ?

`isEven` was supposed to have the signature

You're not using a parameter and your return value doesn't fit the function's name. Try using Alex' `isEven` function and use a conditional operator in `main`. That way you can keep it small.

Thank you

Everything seems good but you might want to crisp short the output statements..

So for Question #1, I got the sequence correct, but don't understand how to apply the % operator apparently. Since 20 % 3 is 6.6666, I should have a result of 6 for the remainder, not 2. I couldn't find the answer to this in the comments below so I must be missing something pretty obvious that no one else got stuck on. Please help.

20 / 3 = 6 remainder 2

because

6 * 3 = 18

and

18 + 2 = 20

Thanks. I was looking at it completely wrong. Now it seems simple. Thanks again.

bool isOdd(int n) {

return (n % 2);

}

interesting that dividing by zero causes a crash but 0%2 works I also had to test 1%2 thinking it would round down, got stuck thinking on that for a bit. never would have come up with "return x % 2 == 0;"

You seem to have mixed up few things. Dividing BY zero causes a crash i.e. 7/0 = ????, but dividing THE zero does not i.e. 0/7 = 0 (if you have 0 pieces of a cake and you want to give each of the seven people a piece of a cake, each person recieves 0 pieces of a cake), same with the modules (%), you can module the zero i.e. 0%2 = 0 (0 / 2 = 0 remainder 0, because 0 * 2 = 0), but you cannot module BY zero i.e. 2%0 (undefined behaviour)

I have a question regarding the use of count as a variable name in this code. My editor which is code::blocks shows count as green text and I tried to search for what it meant and learnt that it was some kind of input iterator. Is it ok to use it as variable name? It looks confusing to me since my count variable is colored green.

Hi!

count is the name of a function in the @std namespace. It shouldn't be highlighted unless you include @<algorithm> and are "using namespace std;", but I guess Code::Blocks is using a static list of words to highlight.

You can use it as a variable name.

can you tell me plz why my code for evan or odds leave me with an error

* Line 16: Initialize your variables with brace initializers. You used copy initialization.

* Line 14: Initialize your variables with brace initializers.

* @main, @isevan: Missing return statement.

* Don't use @std::endl unless you have a reason to.

@isevan is declared to return an int, but it doesn't return anything.

thank you so much

that was realy helpful

but can you give me a reference for when to use brace initializers

Always

Great! Thanks! So that's how it works in code::blocks huh? I was really confused as to why it is highlighted even if I didn't include @<algorithm> on my code.

Hi, this is my answer for quiz 2.

I was wondering if it is okay or there is a problem? thanks.

Hi Ryan!

* Line 13: Initialize your variables with brace initializers.

* "isEven" sounds like the name of a function that returns a value.

* Line 6, 8, 14: Unnecessary space at the end of the line.

Hello!

Regarding part 2 of the quiz, by trying to keep every function as simple as possible, I think I may have overthought this. Could you explain the pros and cons to this method?

Hi!

* Line 6: Don't compare booleans to false/true.

* Line 21: Initialize to 0.

* Print a line feed when your program is done.

The structure of your program is fine. If you can split a function into 2 without making your program harder to understand, it's usually a good decision.

To obey the comment "Print a line feed when your program is done" would it be a better option to omit printAnswer() and add its argument to main() based on the boolean returned from isEven()?

Alright, I wrote a program just for fun, to keep writing code and keep teaching the brain how to write c++ that does some mixed division with Integer and Float inputs and outputs either Integer or Float results.

User can choose whether to use static_cast or not to convert integer inputs to float.

I did it because while reading this page, I felt the need to try several division combinations mixing ints with floats, so here it goes.

The program performs the following division combos:

• Int = Int / Int

• Int = Float / Int

• Int = Float / Float

• Float = Int / Int

• Float = Float / Int

• Float = Float / Float

Note that choosing to convert Ints to Floats makes a difference when calculating Float = Int / Int. You'll know why if you read this class paying attention to what you were reading.

For anyone lurking through the comments that wants to test some division combinations, here is the program:

I'm loving programming. Why didn't I start earlier??

OK, let's jump to the quiz now. =D

Wouldn't it be better to use a bool for your useStatic variable that you're passing to these functions? I mean it only has 2 options right? true and false?

my quiz#2

Hi Dimitri!

* Line 28, 29: Initialize your variables with uniform initialization. You used copy initialization.

* Line 7: Initialize your variables with uniform initialization.

* Line 14: You don't need to modify @x

Thanks nascardriver! Got it! Except * Line 7: Initialize your variables with uniform initialization

Why we need initialization there?

Assuming you're using C++11 or later, it doesn't make a difference here.

Initializing all variables will prevent you from forgetting an initialization where it's necessary.

Oh, OK! Better to assign 1 by default or it doesn't matter?

Whatever is the 0 value for your type.

int 0

float 0.0f

double 0.0

etc

Many thanks!

Hi Alex,

I have a question.

Shouldn't this got to the new line every 2 lines? 2 is evenly divisible by 20 and returns the remainder 0. Why does it still print every 20 lines?

You've got some pretty fancy math. 2/20 = 0,1

*facepalm* I just realized. its late at night and im not thinking straight... sorry xd

2/20 = 0,1

0,1 * 20 = 2

is this / symbol means Division assignment ? @nascardriver

/ division

* multiplication

+ addition

- subtraction

In the isEven() function i can up with:

I read the comments and did not find anyone who did it this way. Is this ok as well or is their a problem with it?

Hi Benjamin!

Logically, your function is equivalent to the other submissions.

But your function is less efficient, because your computer has to perform the extra step of adding 1 to @num.

Thank you! Wow i made two errors in my post. I meant "came* up with" and "or is there*". It was late at night, lol. Again thank you!

While your function mostly works, it will overflow if you pass in the largest integer.

I had the same though, but I came to the conclusion that the overflow doesn't cause any problems, so I omitted it in my reply.

Assuming 32bit integers, 2147483647 (odd) will overflow to -2147483648 (even), same for all integer widths.

The only thing I can think of is that handling the overflow could take up a neglectable amount of CPU-time.

// ConsoleApplication4.cpp : This file contains the 'main' function. Program execution begins and ends there.

//

#include "pch.h"

#include <iostream>

using namespace std;

int getNumber()

{

int x;

cout << "Please enter any number to see if it is odd or even:";

cin >> x;

return x;

}

bool calculate(int x)

{

if (x % 2 == 0)

return true;

else

return false;

}

int main()

{

int x = getNumber();

bool y = calculate(x);

if (y == true)

cout << "its even number.";

else

cout << "Its odd number.";

return 0;

}

My program works fine but i am using different approach.

Can someone please clarify if my approach is fine?

Hi Qais!

* Initialize your variables with uniform initialization.

* In @calculate, you're returning the same value as the == comparison, so you might as well return it directly.

* Don't compare booleans to false/true, they're booleans already.

* Variable names should be descriptive.

Hello there, even my code is working I don't know where should I improve it.So i hope i get some reply.

ps: about even or not even thing in printResult(),i dont know how it works(i guess it evaluates the first parametar if true, and the one after ":" if false), im new to programing, i just saw nascardriver use it in comments some tutorials before and i kinda steal that :)

Hi!

> I don't know where should I improve it

Looks fine to me :-)

> about even or not even thing in printResult [...]

That's the conditional operator. It's covered in lesson 3.4. Your description of how it works is correct.

Thanks for the replay nascardriver.Its very rare experienced programmer taking time to comment a begginer's simple programs.Its a kinda dying breed:)

Looks good, but some suggestions about general practices(more like being nit-picky :))

>> Don't(more like 'No need to') initialize the variables if you are going to override them without using the initialized values.

>> Input argument can be renamed to make it a bit more clear, something like 'is_num_even'

Hi Alex

Firstly, huge thanks for this tutorial series. You have a great teaching style, and I really like how you take the time to talk about good programming practices and pitfalls.

Regarding the following code:

I was playing around with debug->disassembly in VS2017 and noticed that this actually compiles to more instructions in assembly than the if/else version, despite it seeming shorter/simpler in C++.

I didn't check the cycles per instruction, but either way, I thought this tutorial might be a good opportunity for you to bring up the topic of premature optimisation versus code readability (especially as I understand modern compilers can optimise better than most humans, and due to modern CPU features like speculative execution).

I'm just a novice/hobbyist programmer, so I used to be a bit OCD about trying to write efficient code (or at least code that I thought was efficient), including avoiding function calls due to their overhead, but am trying now to re-train myself to prioritise code readability. Personally I think the if/else version is just a tiny bit easier to understand intuitively at a glance.

Thanks again for your work on these tutorials!

Hi David!

Assembly has a very limited instruction set, whereas C++ is huge. You'll get a lot more instructions out of your code, no matter what you write.

Low-level optimization should be left to the compiler in most cases. The programmer should prioritize optimization of algorithms, data usage, etc., because those can't be optimized by the compiler and they have a much bigger impact than a couple of unnecessary instructions.

Yep! I got a little bit of exposure to ARM assembly a while back due to trying to mod some GBA/NDS games. It was fun and I learned a lot, but man is it good to be back in a higher level language and not have to keep track of things like the stack pointer for local variables!!

Agree with your points! I didn't really appreciate that when I started programming though, which is why I thought it might be a good topic for Alex to address in these tutorials as part of good programming practices. Before I was exposed to assembly, I used to think that less C++ code meant less instructions to execute - now I know that is not necessarily the case (for the isEven() example, both versions actually compile into the same assembly for Release build - just 3 instructions)! Now I also know that less instructions does not necessarily equal better performance (or matter nearly as much as algorithms and data usage, as you say).

Hence when it comes to choosing between if/else blocks versus code that looks shorter in C++, I now try to prioritise readability. It might be different for seasoned programmers like yourself, but I have to mentally convert that single line return statement in my head into an if/else statement when reading it anyway, so the if/else version just reads a tiny bit easier for me. The following code from Chapter 3.5 puts this in starker contrast. Also harder to debug I think? Breaking it out into if/else statements made it easier to follow in the debugger for me.

> Also harder to debug

Generally, if you use more lines, it's easier to debug. Using more lines doesn't necessarily change the compiled code.

@approximatelyEqual can be expanded into multiple lines without affecting the outcome. The one-liners might be easier written if you've been coding for a while. But once something goes wrong you'll be back to if/else and temporary variables.

You can edit your posts. The syntax highlighter will work after refreshing the page.

> You can edit your posts. The syntax highlighter will work after refreshing the page.

Ha thanks! That's exactly why I deleted/re-posted. Hope you didn't have to retype your message because of that!

Great conversational points, and the reminder not to prematurely optimize your code is timely as I'm rewriting a lesson where a mention of that would be perfect.

I agree the approximatelyEqual() function is hard to read/follow and even harder to debug -- but I opted to prefer the terse version under the assumption that most readers would just use the function, not try to dissect it. :) Maybe that's the wrong call to make in a learning tutorial series...

> I'm rewriting a lesson where a mention of that would be perfect

Awesome! Is there a way to get email alerts when one of the lessons I've already worked through gets updated (and maybe also see what changed)? Couldn't find a subscribe button anywhere.

> I opted to prefer the terse version under the assumption that most readers would just use the function

Haha I think maybe you also chose it because you knew if you used the long version, you'd have to put up with lots of clever people telling you "did you know you could do that all in one line?" :p I could follow the logic in my head, but needed the debugger to figure out what was happening to the adjusted epsilon for the close-to-zero case. (Who knew multiplying a number by something <1 made that number smaller haha - my maths is sooo rusty!)

On the topic of debugging, I remember a few years ago when I first worked through these lessons (got up to Chapter 14) that the debugger was barely mentioned again after introducing it in Chapter 1 (from a quick site search it seems this is still the case). So back then I never really used the debugger - mostly due to lack of exposure and because I was used to just inserting "debug code" (eg, tracking how variables changed by printing to console), which is a habit I developed from modding games using LUA scripting. But after trying to make sense of ARM disassembly... my God how I appreciate a good debugger now!

As you update lessons for other issues, perhaps it would be helpful to start sprinkling in more exercises using the debugger (just to get new programmers more used to it). For example, in this lesson, the int pow() "exponentiation by squaring" algorithm causes an infinite loop if a negative exponent is entered. You could mention this and encourage students to use the debugger to figure out why (apparently depends on the compiler, but VS17 uses arithmetic shift right for signed int so the loop gets stuck at -1).

(I know you encourage robust code in later chapters, but I used to be super impatient and hate thinking about edge cases or investing the time/lines required. Until I started writing code to parse documents, and kept creating documents that broke my own code or which accidentally created infinite loops. Sometimes ya just gotta learn the hard way...)

There currently isn't an email alert system for lesson updates. It's been a long-standing request that I haven't yet had time to figure out how to facilitate.

> Haha I think maybe you also chose it because you knew if you used the long version, you'd have to put up with lots of clever people telling you "did you know you could do that all in one line?" :p

I didn't think of that, but it's absolutely true. :)

Adding "debug this" quiz questions is absolutely on the agenda as I rewrite. I share your feeling that learning to use the debugger effectively is a crucial skill, and this tutorial series doesn't do a good enough job reinforcing this point.

I appreciate all the feedback! If you have any other thoughts, please feel free to share them.

Hmm, the following WordPress plugins look like they might help? I don't really know much about WordPress or web development though...

https://wordpress.org/plugins/content-update-notification/

https://www.wpbeginner.com/plugins/how-to-show-post-updatesrevisions-to-your-readers-in-wordpress/

Alternatively, there is always the super low-tech but low-cost method: simply create a page to act as a manual changelog. Then from now on, whenever you update a lesson (other than typo fixes, etc) all you need to do is remember to add a one line summary to the changelog page with the date and lesson number.

> this tutorial series doesn't do a good enough job reinforcing this point

Think you're being a little bit hard on your own work there :)

There are a lot of important skills for larger projects or professional development (eg, version control, unit testing, different workflows, automating, etc) that this tutorial series couldn't possibly cover in a meaningful way without overwhelming readers and distracting from its core lessons. (I just spent a WEEK going down a Git rabbit-hole because it's integrated in Visual Studio, and that was just to learn the basics!)

What this tutorial series does do though (ie, cover fundamental C++ programming concepts step-by-step, while teaching good practices and how to avoid common pitfalls along the way), it does really REALLY well. The first time I came across this tutorial series, I had never encountered OOP, overloading, virtual functions and templates before. But this tutorial series made it a real joy to learn!

So thank YOU for all your time and effort!

Since I wanted to write a comment about the int pow() function anyway and I wholeheartedly agree with David about the absolute brilliance (excellence? I don't know what word to use, but it should mean "wayyy better than anything else I have seen") of this website, I will add my 2c here to this thread.

First, let me say that this website has been a Godsend. I am a wannabe musician, and I use MuseScore, an open-source music notation editor written in C++ and using the Qt framework. I wanted to learn to code in C++ to contribute. I have learnt a little programming (Delphi, which is a Pascal framework, and the graphical language Scratch) in high school as an additional subject after school, but I dropped out because I wanted to spend more time with my music. Now I have to brush off my extremely small knowledge of programming and learn a new language.

I just have to say, Alex, you're an awesome teacher. You know in which order to treat subjects so that it makes logical sense, you have a gift for explaining and you know the value of lots of simple, easy-to-understand examples. And that is not all, you also provide very insightful comments into why certain programming practices are bad and why you should avoid them, even if the language allows it. Textbooks never even mention programming best practices. That is the difference it makes when the teacher is working in the industry every day. You know what works and what not. Professors don't necessarily know.

Now, to my comment about the int pow() function:

changing the parameters to

will sort out the problems with the undefined behaviour. You say yourself in the tutorial about bitwise operators that unsigned integers should always be used when doing bitwise operations. It will not violate your rule that you shouldn't mix signed and unsigned integers, since the exponent is never used in an expression with a signed variable.

Hey Louis! Glad to see another huge fan of this website.

Re using an unsigned int parameter for int pow(), just be careful about C++ implicit conversion from int to unsigned int. I know because I previously tried to do exactly what you did, and was surprised that I could pass -1 to exp without any error/warning from the compiler. Not what you want because -1 becomes a very very large unsigned int!

I haven't tried this yet but apparently you can use templates (which is introduced in Chapter 13) to prevent such implicit conversions (see https://stackoverflow.com/a/44412113). If it works, would save on having to do error handling for exp < 0.

Well, yeah, of course C++ would implicitly convert the int -1 to an unsigned int, but I figured it is better to let the loop iterate for a very large finite amount of iterations than to have an infinite loop.

Using unsigned int has the added benefit of telling the programmer that the function expects a positive number. The comment will never be seen if you put the function into a library and write a header file for it.

Maybe the best solution would be to figure out what is the largest exponent you can give the function without overflowing the int return value and test to see if your unsigned int is smaller than that. You should just use sizeof(int) to figure out if you are dealing with 16-bit or 32-bit ints.

I didn't read the stackoverflow thread yet when I wrote this. I'll have a look, but I did not get to templates yet. I restarted reading the tutorials about at the new year, because I stopped reading for quite some time and had to recap. I never read further that Chapter 9's comprehensive quiz.

> Well, yeah, of course C++ would implicitly convert the int -1 to an unsigned int...

It wasn't obvious to me!! But yeah, infinite loops suck. One good thing about them though is it alerts you to a problem, whereas an incorrect result might go undetected - probably doesn't matter for the kind of things we're programming, but could be disastrous in something like aircraft software!

Templates (and virtual functions) are pretty fun when you get to them, once you wrap your head around the syntax. It's basically like a souped up version of overloading, but the compiler does some of the hard work for you.

Thanks for the kind words!

Using an unsigned parameter violates the "don't use unsigned integers except for bit-level operations", and also the "don't use unsigned values just to avoid negative numbers" rule (not sure if I've made that one explicit, I'll check and make sure I have).

The correct solution here is to use a signed parameter, but then use an assert or other precondition (in C++20, expects) to validate that the value actually is negative.

As David correctly notes, you'll still get conversions if you pass in a signed value as the parameter.

@Alex, while I agree with your rules, I disagree that using an unsigned int is breaking them. Here is the function so you don't have to scroll up to see it:

and here is my proposed change with clarifying comments:

You would still need to assert the exp argument is not negative, but even if you do that, an unsigned int is better because you are using it for bit-level operations. Else you might anyway get undefined behaviour, even if you ensure that exp >= 0.

We normally would choose unsigned for bit-level manipulation because we don't want surprises from the sign-bit. But:

1) Such surprises can't happen in this case -- if exp must be positive (which we can enforce via assert or templatization), then the sign bit should always be 0, and we only do right shifts, so the sign bit never has a chance to flip.

2) We're treating this value as a number, not a sequence of bits. The bit manipulation here is an optimization, not a necessity (we could have used arithmetic instead, it just would have been slower).

Given the above, I'd still favor signed because then we can detect/handle the case when the caller passes in a negative value (even though the sample code doesn't, for simplicity), whereas with unsigned we can't (and we get a silent failure -- the worst kind).

Ok, so do I understand correctly that bitshifts on signed positive integers (sign bit = 0) is defined? It is just the bitshifts with negative integers which exhibit undefined behaviour. (Some compilers pad with 0s and other compilers pad with 1s when you shift a signed int with a 1 in the sign bit to the right?)

Also, is bit operations with positive signed integers defined by the C++ language standard, or is it just a case of everybody agrees on how they should work, even if it isn't defined?

Yes, I believe bit operations and binary representation for positive integers (and zero) are well defined by the C++ specification. It's only negative numbers that have issues, due to the fact that they can be encoded in different ways.

You are correct. I looked it up here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf It is in Chapter 5.8.

Bitshifts are defined by the standard for unsigned ints and non-negative signed ints as long as the result can be represented in the left operand's data type. For negative ints, the result is implementation-defined.

So I gave myself a challenge to write a geometric sequence and then display the last number in the sequence and state whether it's even or odd.

1. Is there any way I can improve this

2. I'm beginning to understand while loops. How do I do this:

if the user inputs a decimal number for "Enter a power: ". It'll output an speech and loop them back to question "Enter a power: " again until they give an integer without decimal point.

Hi Rai!

1.

* Initialize your variables with uniform initialization

* Line 32: You can use single quotation marks to make your numbers more readable (1'000'000)

* Line 32: This loop could be infinite if @power <= 1

* Use double numbers when calculating with doubles (1.0 instead of 1 etc.)

2.

Thanks. One thing. You told me about Initialize your variables with uniform initialization before but I don't understand what this means - how to use {} to initialize variables. Could you show an example.

This is part of lesson 2.1. Unfortunately, Alex doesn't use uniform initialization himself in most of the lessons.