This challenge is all about arithmetic. While most of it will be familiar from maths, in programming there are some odds and ends that we need to talk about.
- Insert a command that lets the turtle show a simple calculation:
Turtle.Say("5 + 2 = 7");
.That’s good, but we don’t learn C# to do calculations by hand, do we?
- Change the command so that the program does the calculation:
Turtle.Say($"5 + 2 = {5 + 2}")
.The first time we used string interpolation we simply put a variable inside the curly braces
{
and}
. But in fact we can put any expression inside the curly braces – the result of the expression is then interpolated into the string. - In C# we can do all four basic arithmetic operations: addition (
+
), subtraction (-
), multiplication (*
) and division (/
). Try them all and see if they work as expected.Add
Game.WaitForMouseClick();
after every command. Otherwise the turtle would have said everything in a blink of a second. This command pauses execution until you click somewhere at the scene. - Check if operator precedence rules apply. Is multiplication and division calculated before addition and subtraction?
You can even change the precedence by using parentheses
(
and)
. - That’s nice, isn’t it? No surprises so far. Try some calculations with real numbers as well.
Notice that C# uses a dot
.
as decimal separator. Depending on your origin this might be odd. - Everything seems to work fine, right? Just out of curiosity try to calculate
17 / 7
and check the result.Wait, what just happend? That can’t be right.
C# knows two types of division, and in our case it used the one that we are probably less familiar with. The two types are:
- Division of real numbers: This is the one you most likely are familiar with. The result of this division is a real number.
- Division of integers: The result of this division is an integer where the fractional part of the real quotient is cut off.
C# decides to do integer division if both operands are integers. If at least one operand is a real number, it does real division and we get a real number as result. An integer can be turned into a real number quite easily by appending
.0
at the end, so in the above example we get the real result if we wrote17.0 / 7
. For variables it’s slightly more verbose. If you havea / b
and botha
andb
are of typeint
– shorthand for integer – you need to convert at least one of them to adouble
by prepending(double)
, for example(double)a / b
. This conversion is typically called cast. Here is the full example:int a = 17; int b = 7; double result = (double)a / b;
- Maybe integer division is not as unfamiliar as it initially seemed. When doing division by hand you might have learned to calculate the integer quotient as well as the remainder. C# has an easy to use operator to calculate the remainder because there are many use cases for remainders. To calculate the remainder of a division you use the modulo operator
%
, for example17 % 7
.
As you probably know from maths there is an infinite number of integer values and an even larger number of real numbers. But in C# we only have four bytes to represent an int
and eight bytes for a double
, so the number of different values is limited. Let’s explore those limits and see what happens when we exceed them.
- Let the turtle tell us the minimum and maximum value for
int
usingTurtle.Say($"Minimum int: {int.MinValue}\r\nMaximum int: {int.MaxValue}");
.You can think of
int.MinValue
andint.MaxValue
as variables except that you can’t store another value in them. They are constant. - If
int.MaxValue
is the maximum number that we can respresent with four bytes, what happens when we increase it by 1? TryTurtle.Say($"Maximum int + 1: {int.MaxValue + 1}");
?C# apparently is smart enough to detect an overflow and prevents us from running the program. We can tell C# to ignore overflows by using
Turtle.Say($"Maximum int + 1: {unchecked(int.MaxValue + 1)}");
. While very useful for demonstration purposes it’s very unlikely that you’ll ever need theunchecked
operator. If you look at the binary representation of anint
value in C# – which we are not going to do because this challenge is already complicated enough – it’s very obvious whyint.MaxValue + 1
equalsint.MinValue
. - Try the same experiment with
int.MinValue
.
The internal representation of real numbers is much more complicated because of the fractional part. The most obvious thing to do would be splitting the eight bytes of a double
into four bytes for the integer part and four bytes for the fractional part – this is called fixed-point representation. However most systems use floating-point representation which gives a much wider range of possible values but in exchange suffers from a loss of precision which we are going to explore now.
- Add the command
Turtle.Say($"0.1 + 0.2 = {0.1 + 0.2:R}");
and check the result.:R
after the calculation prevents rounding the value. Again we use this here for demonstration purposes. In real life this is needed very rarely.It’s not important why exactly we have a rounding error in this calculation, but the take-away from this lesson is that a computer can’t represent all real numbers (not even close) and that we have to be very careful when working with such numbers.
- Check the bounds of
double
as we did before withint
. - Try to overflow it by multiplying
double.MaxValue
by 2 and see what happens. - Try the same experiment with
double.MinValue
.