Intermediate5 InfinityType conversion



The day came when I met Infinity. She was from the central resistance base, called 'Wonderland'. Every month, Ritchie had been sending the 10 best programmers from his base to Wonderland, for participation in the Rust project.
"Wait!" - I realised I had just said 'best programmers'. "Does this mean that I'm one of the top 10 best programmers that Ritchie has?! Cool!" - I hadn't even thought about that until now.
"Are you listening to me Teo?" Infinity stopped my thoughts, asking a question.
"Sure, sorry... please continue." I replied.
"This is gonna be hard. You'll be in the central base with the best programmers we have. Your mission in the Rust project will be top secret; you will not be able to talk about it to your friends."
Friends? She said friends ?! Does she know that I have literally nobody on my own here?! That I'm completely alone?! That my best friend is a machine that I still don't trust?! She must be kidding!
"I looked through your code Teo... And I was surprised at how quickly you've improved! Take your first and last programs for example; this is astonishing! But at the same time, I've realized that whoever was training you, is only choosing data types that match each other. You have never used the type conversion technique."
"Type conversion?!" I hadn't heard of that before.
"Let's take some time Teo, and I'll go through this topic with you right now." she replied.

Convert me

Infinity began, "Here is a table of built-in types in C#. Some of them you already know, but others could be new for you":

Data Type Size (bytes) Range
1 0..255
1 -128..127
2 -32,768 .. 32,767
2 0 .. 65,535
4 -2,147,483,648 .. 2,147,483,647
4 0 .. 4,294,967,295
8 -9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807
8 0 .. 18,446,744,073,709,551,615
4 -3.402823e38 .. 3.402823e38
8 -1.79769313486232e308 .. 1.79769313486232e308
16 -79,228,162,514,264,337,593,543,950,335 .. 79,228,162,514,264,337,593,543,950,335
1 True or False
2 A unicode character (0 .. 65,535)

"My God! Do C# programmers remember all these types, their sizes and ranges off by heart?!" I wondered.
"Most of them... not. What you need to know, is when to use each of those."
"Yeah, for example, byte , short , int - they're almost the same, so why can't I just use int all the time?" I naively asked.
"Well... you can! It depends on the constraints that you have. If you have 50 000 small integers that you need to send over the network, then a byte array can be preferable over an int array, as it will save memory space and increase the speed." she explained.
"For now, let's make a deal, that if you have no special requirements for the task, then use int for integer numbers and double for fractional numbers. "
"OK, I will do. I've already been doing this so far..." I replied, "Wait - can you please tell me, what does that 'u' mean at the beginning of some of the types?"
" u originates from 'unsigned' . If you look carefully, you'll notice that types that start with u , do not have negative values. In general, you can use int , uint , short , ushort , long and ulong in a very similar way - look at this code example and solve the task after it":

byte byteVariable = 12;
short shortVariable = 12;
int intVariable = 12;
long longVariable = 12;

// Use short.Parse long.Parse byte.Parse same as int.Parse
short anotherShort = short.Parse(Console.ReadLine());
var yetAnotherShort = short.Parse(Console.ReadLine());

Console.WriteLine(byteVariable);  // Outputs 12
Console.WriteLine(shortVariable); // Outputs 12
Console.WriteLine(intVariable);   // Outputs 12
Console.WriteLine(longVariable);  // Outputs 12

C# transformation

Infinity continued, "As you know, in C# every variable has a type. It's impossible to change the type of a variable, but you can convert a value from one type to another and then store it into a new variable. There are two kinds of type conversion: implicit and explicit . Implicit conversions happen without us as programmers even noticing it ! Here is an example of implicit type conversion":

short shortNumber = 23;

// Implicit conversions
int intNumber = shortNumber;
float someFloat = shortNumber;
double firstDouble = intNumber;
double secondDouble = shortNumber;

// Wrong, no implicit conversion
intNumber = firstDouble;

"As you'll see, I've created a short variable and assigned it to int , float and double . Everything is fine; implicit conversion happens, and you store the value from a variable of one type, into a variable of another one." Infinity explained.
"This is a bit confusing!" I exclaimed. "How would I know that implicit conversion between two types exists?"
"Good question Teo! There is a general rule: implicit conversion exists from 'small' types, to 'bigger' ones, counted by the amount of bytes the type takes . For example, there is an implicit conversion from byte to int , but not vice versa; from int to byte ."
"It makes some sense now... So, if inside an int variable, I have a big number - let's say 1000, and I try to store it inside a byte variable, it won't fit into the range [0-255]?" I shared my thoughts.
"Yes, that's exactly the reason Teo. If I have an int that takes 4 bytes, it's impossible to fit it into a byte type that is only 1 byte big. Here is a complete C# Implicit Numeric Conversions Table , or you can just use a subset that I've picked for you":

From Type To Types
short, ushort, int, uint, long, ulong, float, double or decimal
long, float, double or decimal
ushort, int, uint, long, ulong, float, double or decimal

I started to like her. She was smart, wasn't aggressive and explained things really well. Perhaps I wouldn't be so disappointed about working with her if I had no backup plan (like returning home with Noname's help).
"Good job Teo! There is one more type conversion technique — the explicit conversion . It is also called a cast . A cast is a way of explicitly informing the compiler that you intend to make the type conversion, and that you are aware that data loss may occur. To perform a cast, specify the type that you are casting to in parentheses(), in front of the value or variable to be converted. Here is an example where we cast double to int ":

double a = 123.95;
int b = (int)a; // Explicit cast

Console.WriteLine(b); // Outputs 123

"This looks powerful!" I proclaimed. "Could you please show me some more cast examples?"
"No problem, here you go! Oh, and don't forget about the exercise after below the example!":

double someDouble = 123.95;
float someFloat = (float)someDouble; // No data loss, someFloat == 123.95

double anotherDouble = 123.456789098765;
float anotherFloat = (float)anotherDouble; // Data loss, anotherFloat == 123.4568

long someLong = 123;
int someInt = (int)someLong; // No data loss, someInt == 123

long anotherLong = 112233445566;
int anotherInt = (int)anotherLong; // Data loss, anotherInt == 564295870

int yetAnotherInt = 123;
byte someByte = (byte)yetAnotherInt; // No data loss, someByte == 123

int intToConvert = 1234;
byte resultAsByte = (byte)intToConvert; // Data loss, intToConvert is too big to fit into byte

// Multiple conversions in expression are also fine
int intResult = (int)someLong + (int)anotherDouble; // Data Loss, intResult == 246
float floatResult = (float)anotherDouble + (float)someDouble; // Data loss, floatResult == 247.406784

// Conversion of the operation's result is fine as well
int anotherIntResult = (int)(someLong + anotherDouble); // Data Loss, anotherIntResult == 246
float floatResult2 = (float)(anotherDouble + someDouble); // Data loss, floatResult2 == 247.406784

"So, take this very simple task. You have some cupcakes and some people that all want one! You need to share among people fairly, so that everyone gets an equal amount of cupcakes. Your program should read an int (amount of cupcakes), and another int (amount of people). Then, it should output "Every person should get {amount} cupcakes"
"This seems simple; you just need to divide 2 numbers... do you want me to write the code?" I asked.
"Go ahead!" she said, a little too positively.
It was clear that something wasn't quite right. She was smiling and staring straight at me.
"But... I'll write the code." I uneasily thought to myself.

int cupcakesCount = int.Parse(Console.ReadLine());
int peopleCount = int.Parse(Console.ReadLine());

double result = cupcakesCount / peopleCount;

Console.WriteLine($"Every person should get {result} cupcakes.");

"Okay, let's run this code with 3 people and 6 cupcakes" she said.
The code ran fine; the result was - "Every person should get 2 cupcakes"
She continued, "But, what if we have only 1 cupcake and 4 people?"
When we tried my code with these parameters, the output was - "Every person should get 0 cupcakes"
"Why is it 0? It should be a quarter (0.25) of a cupcake for everyone!" I firmly yelled, frustrated.

C# is sometimes complicated

"Well, it's because of the type conversion. When you perform an arithmetic operation with integers, you'll always get an integer as a result. This works for short , byte , float and all other primitive types that we've used.
"What does this mean Infinity?!" I asked.
"This means, that you should be careful when dividing int types. C# compiler isn't able to understand that you want a float or double as a result, unless you specifically tell it this. Otherwise, it will disregard the fractional part . Here, I've prepared some examples":

int a = 9;
int b = 4;

double firstAttempt = a / b;
double secondAttempt = (double)a / b;
double thirdAttempt = a / (double)b;
double nextAttempt = (double)a / (double)b;
double lastAttempt = (double)(a / b);

Console.WriteLine(firstAttempt);  // Outputs 2
Console.WriteLine(secondAttempt); // Outputs 2.25
Console.WriteLine(thirdAttempt);  // Outputs 2.25
Console.WriteLine(nextAttempt);   // Outputs 2.25
Console.WriteLine(lastAttempt);   // Outputs 2

Console.WriteLine( (int)2.25 );            // Outputs 2
Console.WriteLine( (int)secondAttempt );   // Outputs 2

"As you'll see Teo, there are a lot of ways to cast types. The main rule here is ' if there are several operands in the expression, then the type of the result is the largest of the operand types'. For example, if you divide int and double , the result is double . If you multiply byte and int , the result is int . In tasks that you are going to solve in the future, make sure you don't forget to cast to double or float during int division. If you forget, you'll lose the fractional part, just like in the cupcakes example!"

Great job!