Course Intro & Overview
C# Data Types and Variables
In this course, we look at how different types of data are stored using variables within a C# program. C# is a strongly typed language, meaning when you manipulate data in code, you must keep the data in variables that are specifically designed to hold that kind of data. For example, text is stored in a string data type and a letter in a char. There are over ten different numeric data types that vary in size and accuracy or precision of the data they can faithfully represent. We investigate some of the quirks in dealing with fractional numbers in a computer's binary environment. There are in-depth code examples for each of these topics to illustrate the discussed concepts and make you more familiar with C# programming in general.
This course builds upon the key concepts and examples covered in the Introduction to C# course. It includes guided demonstrations to give you practical knowledge of how to handle the concepts covered.
- Understand what variables are and how they're stored
- Learn about data types for storing and manipulating text values
- Learn about the various data types for storing and manipulating whole and fractional numbers
- Learn about variables for storing multiple values of the same data type
This course is intended for anyone who has a basic understanding of C# and now wants to build upon that knowledge.
This course carries on from our Introduction to C# course, so we suggest taking that one first if you haven't already done so.
Code examples used in demos on GitHub
Now, I want to explore the quirks of floating-point numbers that we discussed earlier by creating a new .net console application, this time in the Ubuntu environment. I am creating the app with the .net new command, giving it the name FloatingPoint. Once created, I'll CD into that directory and fire up Visual Studio Code with the code command. I'll say Yes to add the required assets.
The first thing I want to explore is how the different floating-point datatypes deal with adding two numbers together. So I'll start with float, and the numbers that we'll add together are 3.65 and 0.05, which should equal 3.7. I'll repeat the same piece of code for double and decimal data types, with a different answer variable appropriately prefixed for each.
You may be thinking that the text I'm writing to the console is just going to be three copies of "float answer should be 3.7 but is fAnswer" in curly braces. At the beginning of the string, there is a $ sign, telling the C# compiler that the string is interpolated. An interpolated string will treat anything within curly braces as a variable rather than a literal text.
When I run this code, the answer variable's value for float, double, and decimal will be displayed, not the variable name. Using string interpolation is the preferred method for displaying variables within strings over joining strings with the addition or plus operator. I've appended the literal input character after the numbers being added, so f for float, d for double, m for decimal.
Let's see what the output is when I run this without debugging within the VSCode terminal window. Well, that's quite interesting. Float and decimal return the correct answer, but for different reasons, while double returns a number very close to 3.7 but not precisely 3.7. Decimal returns the correct answer because it is the most precise floating-point data type. Float returns the correct answer because it's not precise enough, and it is rounded to 3.7.
It is double that gives us an insight into binary representations of floating-point numbers. We can also see how different floating-point data types treat numbers by comparing results that we know should be different. What I'll do now is multiply .09 x 100, assigning the product to the existing answer variable and compare it to .09 multiplied by 99.99999, assigning to a new answer variable. I'll do this for float, double, and decimal.
To evaluate the comparison, I'm going to introduce you to another data type called a bool, which is short for Boolean. A bool variable can store one of two states. It can be either false or true. Here I've created a bool variable called areEqual, and it is assigned the value of true or false depending on whether fAnswer is equal to fAnswer2.
In C#, we use the equal operator to assign values to variables, so when we want to compare values to see if they are equal, we use two equal signs together. The syntax is common to many programming languages like Java, C, and C++. Apart from equality, Boolean operators include greater than, less than, and not. Not and equals can be combined together with greater than and less than, so we can have less than or equal to and greater than or equal to.
First, I'll check the code for float is working before moving on to the other data types. For double and decimal, I'll add quite a few nines after the decimal point. Let's see what our results are when we run that. This time it is only the decimal data type that correctly shows the two expressions to be different.
Let's see what happens when I change the 0.09 from a double to a float literal, remembering that we can mix and match doubles and floats but not with decimals. That's interesting; because of the difference in precision between doubles and floats, I've introduced a rounding error, so the correct answer of nine is now wrong, and we still have the wrong answer to 0.09×99.99999. We do get the correct answer of false to the comparison between the double variables, but it is right for the wrong reason. I guess this is a case where two wrongs do make a right.
Let's see what happens when we divide one integer value by another to produce a fractional result and assign the answer to the double variable dAnswer. I'll declare an int variable called one and give it the value 1 and an int variable ten and give it the value 10. Next, I'll divide 1 by 10 and assign it to dAnswer, outputting the result to the console. We expected 0.1, and we got zero.
Integer arithmetic only returns integer values. If I change the one variable value to 7 we still get zero, but if I change it to 15, then we get one. This tells us that the integer arithmetic is ignoring or discarding any fractional part of the result, even if it is being assigned to a floating-point variable. To get the correct answer let's try casting the division expression as a double before assigning it to dAnswer.
First, I'll just change the word float to double to say what's going on correctly, and then change the 15 back to 1. Next, cast the whole division expression as a double before assigning it to dAnswer. Unsurprisingly, that doesn't work as the expression is still an integer division, so casting it to a double after the fact makes no difference. The only way to get the correct answer is to cast each integer variable individually as a floating-point data type. If I do that, then we get the right answer.
Hallam is a software architect with over 20 years experience across a wide range of industries. He began his software career as a Delphi/Interbase disciple but changed his allegiance to Microsoft with its deep and broad ecosystem. While Hallam has designed and crafted custom software utilizing web, mobile and desktop technologies, good quality reliable data is the key to a successful solution. The challenge of quickly turning data into useful information for digestion by humans and machines has led Hallam to specialize in database design and process automation. Showing customers how leverage new technology to change and improve their business processes is one of the key drivers keeping Hallam coming back to the keyboard.