Wednesday, 10 August 2016
Type Casting, Numbers
This is a simple exercise, but an important one nonetheless. When you start to deal with keeping score, or recording injuries to a monster, it’s important that behaviors are predictable. Many problems begin to show up if the math you’re using involves mixing numbers with decimal values like floats or doubles, or with integers which have no decimal value.
Converting types between one another is pretty simple when you need to deal with numbers. When we start creating our own classes the task of casting becomes a bit more detailed, but not necessarily more difficult; there’s just a bit more work involved. We’ll get to that soon enough.
When we go between number types or the built-in value types (POD), we work with things which seem to come with C#. So far we’ve seen things like int and float. Integer values like 1, 7, and 19 are useful for counting. We use these for counting numbers of items in an array, or how many zombies are in a scene, for instance. Integers are whole numbers, even though we might be counting zombies whole or not.
Once we start needing numbers with fractions we need to use float values. To get an object’s speed or x, y, and z coordinates in space we need to use values like 12.612f, or x = 13.33f, to accurately place an object in space. If not, objects would move around in a scene as though they were chess pieces locked to a grid.
When a float value exists as 0.9f we lose some values after the decimal when converting the floating point value to an integer.
The first part of the error message says “Cannot implicitly convert type,” which has a very specific meaning that we’ll get to before the end of this chapter, but first let’s cover explicit type casting.
Explicit versus Implicit Casting
As we have seen, in the Start () function where we declared float a = 0.9f; a was converted to 0. Even though we were only 0.1f away from 1 and 0.9f away from 0 we’re left with a 0 instead assigned to int b. To do these conversions we use the explicit casting method, as shown with (int)a;, which explicitly tells C# to convert the value stored at a to a float value. When we are required to use an explicit cast, we’re also warned that there may be some data lost in the conversion.
Casting is a process by which C# changes the type of a variable to another type. This may or may not involve a loss of information. In some cases, the conversion doesn’t require the explicit cast operator. The following code casts an int to a float.
There are no integer values which will result in a loss of any value when it’s converted to a float. Technically, there are more float numbers between 0 and 1 than there are integer numbers between 0 and 1, or any other sequence of two numbers for that matter.
A Basic Example
Create a new project called NumberTypes and assign a C# script to the Main Camera called NumberTypes.cs. In the Start () function include the following code.
int c = a * (int)b;
We use type conversion to tell C# to explicitly change b from a double to an int by preceding the b with (int). What value is going to be assigned to c if it can’t be 0.9? The (int) operator is an explicit cast.
We will find other casts which look like this in Sections 6.14 and 6.20, but we’re introducing the concept early on as it’s a very common problem to come across. The syntax (int) turns a number following this operator into an int.
Likewise
Some conversions take place automatically as an implicit cast. In the above example we can use the following code without any problems.
When mashing a double into an int we lose the mantissa and exponent. By using an explicit cast, we tell C# that we don’t mind losing the data. This doesn’t mean that an implicit cast will not lose any data either. An int can hold more significant values than a float. We can observe this with the following lines of code added to the Start () function.
If we cast this into largeFloat we can use an implicit cast, which converts the value from int to float. In this case we see only 2.147484 followed by the exponent E+09, which tells us that the dot (.) is actually nine places over to the right.
When we convert the float back into an int with an explicit cast we get a −2147483648, which is certainly not what we started with. This tells that there’s some significant information lost in the conversion from float to int, but there were also numbers lost in the implicit cast from int to float.
This still happens if we remove a digit from the end.
Logically, another difficult problem is converting from a string to a number value. When you use string s = "1"; you’re not able to use (int)s to convert from a string to an int. The types of data are very different since strings can also contain letters and symbols. The conversion of (int) "five" has no meaning to the computer. There’s no dictionary which is built into C# to make this conversion.
This doesn’t mean that there are no options.
int i = 100;Decimals are not allowed on an int value.
float f = 100.0f;Decimals are allowed for both float and double. The only caveat is that a float requires an f post fixed to the number when it’s assigned.
double d = 100.0;
Converting types between one another is pretty simple when you need to deal with numbers. When we start creating our own classes the task of casting becomes a bit more detailed, but not necessarily more difficult; there’s just a bit more work involved. We’ll get to that soon enough.
When we go between number types or the built-in value types (POD), we work with things which seem to come with C#. So far we’ve seen things like int and float. Integer values like 1, 7, and 19 are useful for counting. We use these for counting numbers of items in an array, or how many zombies are in a scene, for instance. Integers are whole numbers, even though we might be counting zombies whole or not.
Once we start needing numbers with fractions we need to use float values. To get an object’s speed or x, y, and z coordinates in space we need to use values like 12.612f, or x = 13.33f, to accurately place an object in space. If not, objects would move around in a scene as though they were chess pieces locked to a grid.
When a float value exists as 0.9f we lose some values after the decimal when converting the floating point value to an integer.
void Start ()If we use the above code in a new script called Casting.cs attached to the Main Camera in a new Unity 3D project we’ll get the following output to the Console panel.
{
float a = 0.9f;
int b = (int)a;
Debug.Log(b);
}
0Without the cast operator int b = a; we get an error telling us we need to cast the value before assigning it.
UnityEngine.Debug:Log(Object)
Casting:Start () (at Assets/Casting.cs:10)
Assets/Casting.cs(9,21): error CS0266: Cannot implicitly convert type ‛float’ to ‛int’.
An explicit conversion exists (are you missing a cast?)
The first part of the error message says “Cannot implicitly convert type,” which has a very specific meaning that we’ll get to before the end of this chapter, but first let’s cover explicit type casting.
Explicit versus Implicit Casting
As we have seen, in the Start () function where we declared float a = 0.9f; a was converted to 0. Even though we were only 0.1f away from 1 and 0.9f away from 0 we’re left with a 0 instead assigned to int b. To do these conversions we use the explicit casting method, as shown with (int)a;, which explicitly tells C# to convert the value stored at a to a float value. When we are required to use an explicit cast, we’re also warned that there may be some data lost in the conversion.
Casting is a process by which C# changes the type of a variable to another type. This may or may not involve a loss of information. In some cases, the conversion doesn’t require the explicit cast operator. The following code casts an int to a float.
int c = 3;
float d = c;
Debug.Log(d);With the above code we get a 3 printed out to the Console panel. We didn’t need to use an explicit casting operator. This is because when we cast from an int, in this case 3, there would be no data loss when it’s cast to a float. This is possible through an implicit cast. Implicit casts are allowed only when there is no data lost in the process of converting from one type to another.There are no integer values which will result in a loss of any value when it’s converted to a float. Technically, there are more float numbers between 0 and 1 than there are integer numbers between 0 and 1, or any other sequence of two numbers for that matter.
A Basic Example
Create a new project called NumberTypes and assign a C# script to the Main Camera called NumberTypes.cs. In the Start () function include the following code.
void Start ()
{
int a = 1;
double b = 0.9;
int c = a * b;
Debug.Log (c);
}If we look at what is going on here we’ll want to think for a moment about what it means. The integer a is set to 1 and double b has 0.9 assigned. We should assume that 0.9 will be assigned to c after the multiplication, but this assignment is stopped by a type conversion error. C# usually gives us pretty clear reasons for its errors. In this case we know there’s a cast missing between an int and a double.Assets/NumberTypes.cs(10,21): error CS0266: Cannot implicitly convert type ‛double’ to ‛int’. An explicit conversion exists (are you missing a cast?)The error states we can’t implicitly convert a double to an int; why not? 1 certainly looks like 1.0, or so it seems. However, 0.9 can’t be turned into an integer. There’s no integer between 0 and 1. Even though 0.9 is very close to being 1, it’s not.
int c = a * (int)b;
We use type conversion to tell C# to explicitly change b from a double to an int by preceding the b with (int). What value is going to be assigned to c if it can’t be 0.9? The (int) operator is an explicit cast.
00 is less than 0.9; we’ve lost data going from the double value to an integer value. Even though 0.9 is almost a 1, the first int value is 0, followed by values that are cut off by the type conversion. This is why type conversion matters.
UnityEngine.Debug:Log(Object)
NumberTypes:Start () (at Assets/NumberTypes.cs:11)
We will find other casts which look like this in Sections 6.14 and 6.20, but we’re introducing the concept early on as it’s a very common problem to come across. The syntax (int) turns a number following this operator into an int.
Likewise
int i = 0; double d = (double) i ;is a way to cast an int into a double. However, this isn’t always necessary.
Some conversions take place automatically as an implicit cast. In the above example we can use the following code without any problems.
void Start ()Here we assign double d = a; where a is int 1, which we know isn’t a double. This produces no errors. The same goes if we add another line float f = a;. In this case f is a float. These are called implicit casts. An integer value doesn’t have a mantissa or an exponent. Both the double and float do have these two possibly large and important values. These two terms were explained at the end of Chapter 2.
{
int a = 1;
double b = 0.9;
int c = a * (int)b;
Debug.Log (c);
double d = a;
Debug.Log(d);
}
When mashing a double into an int we lose the mantissa and exponent. By using an explicit cast, we tell C# that we don’t mind losing the data. This doesn’t mean that an implicit cast will not lose any data either. An int can hold more significant values than a float. We can observe this with the following lines of code added to the Start () function.
Debug.Log(largeInt);This code produces the following console output, after a bit of cleaning up:
float largeFloat = largeInt;
Debug.Log(largeFloat);
int backAgain = (int)largeFloat;
Debug.Log(backAgain);
2147483647When we start with the value 2147483647 assigned to int we’re at one extreme of the integer value. This is the biggest number the int can hold, for reasons discussed in Section 3.11.1, but in short, it’s because it’s using only 32 bits to store this number.
2.147484E+09
-2147483648
If we cast this into largeFloat we can use an implicit cast, which converts the value from int to float. In this case we see only 2.147484 followed by the exponent E+09, which tells us that the dot (.) is actually nine places over to the right.
When we convert the float back into an int with an explicit cast we get a −2147483648, which is certainly not what we started with. This tells that there’s some significant information lost in the conversion from float to int, but there were also numbers lost in the implicit cast from int to float.
This still happens if we remove a digit from the end.
int largeInt = 214748361;//cutting off a digit and ending in 1This sends the following numbers to the console:
Debug.Log(largeInt);
float largeFloat = largeInt;
Debug.Log(largeFloat);
int backAgain = (int)largeFloat;
Debug.Log(backAgain);
214748361The last digit is changed from 1 to 8. The 8 is coming from some strange conversion when we go from int into float. Even if we look at the numbers being stored in the float value we can tell that there’s already a change in value. This tells us that in general, we need to be very careful when converting from one type into another.
2.147484E+08
214748368
Logically, another difficult problem is converting from a string to a number value. When you use string s = "1"; you’re not able to use (int)s to convert from a string to an int. The types of data are very different since strings can also contain letters and symbols. The conversion of (int) "five" has no meaning to the computer. There’s no dictionary which is built into C# to make this conversion.
This doesn’t mean that there are no options.
string s = "1";The code added to the Start () function will produce the following number:
int fromString = int.Parse(s);
Debug.Log(fromString);
1There are plenty of options when faced with dealing with significantly different types. The int.Parse() function is an option that we can use to convert one value into another. Again, we might be getting a bit ahead of ourselves, but it’s important to see that there are many different ways to convert between different types.
Subscribe to:
Post Comments
(
Atom
)
No comments :
Post a Comment