The Prism Primer - Part 7

From The Oxygene Language Wiki

Jump to:navigation, search

This is a General topic
Feel free to add your notes to this topic below.


The Prism Primer: Part 1Part 2Part 3Part 4Part 5Part 6Part 7Part 8Part 9


Number Representation

In this section we'll (finally!) finish the calculator sample. A good calculator should be able to work with rational number ("comma numbers").

Working with such numbers is a little bit tricky, because of the way they're stored inside a computer. Because this is very important for the every-day-use, we'll have to get a little bit deeper into the basics of this topic.

Representation of Integers

A good introduction is, to look at how we represent numbers in our "normal" life. We use them constantly, but we don't have to remember the system behind them. We just "use" them.

Lets take the number 1234. This sequence of digits is the short form of this calculation:

     4 times 1    = 4*100
plus 3 times 10   = 3*101
plus 2 times 100  = 2*102
plus 1 times 1000 = 1*103

Thus the digits represent multiples of powers of ten which are summed up to get the number. The number of which we calculate the powers (in this case 10) is called the basis of a number representation or numeral system. If the basis is 10 you talk about a decimal system!

Representing numbers using a basis of 10 is not very clever when doing this in computers. A binary system (using a basis of 2) is much better. Here's a short sample on how to write a number in the binary system:

12 = 
          0 times 1 = 0*20
     plus 0 times 2 = 0*21
     plus 1 times 4 = 1*22
     plus 1 times 8 = 1*23
= (1100)2

To make clear for which basis we write a number, you enclose the number in braces and add the basis as index: (...)b. If the basis isn't given, we assume it's 10. The basis is always written as decimal number.

There's another important numeral system in informatics: the hexadecimal system, which uses a basis of 16. If you have used some kind of graphics program, you'll know this system as the one used to specify colors, e.g. FF33AA. Because we only know digits from 0 to 9, values from 10 to 15 are represented by the letters A to F.

You can split the color value into three values with two digits each. The three numbers then represent the red, green and blue parts of the color. Each number can have values from 0 to 255, which is exactly one byte of memory!

Representation of Rational Numbers

In most cases you'll use a different system to represent rational numbers in a computer. In our every day use we just use the same system "behind the comma":

42.13 = 
          4 times 101
        + 2 times 100
        + 1 times 10-1
        + 3 times 10-2

The exponents are carried out into the negative range, so we are calculating with tenth and hundrets.

You can find this system in informatics, too, but is not very often used. Assuming that there's a fixed number of digits (= memory) per number available, the comma is always at the same position. It's predefined how many digits can be in front of the comma (in other words how big the number can get) and how many are behind the comma (in other words what precision is avaiable). You call that number a fixed-point number for obvious reasons.

In most cases a floating-point representation will be used, where the position of the comma isn't fixed. The scheme for this representation is:

       z = m * be
e.g. 300 = 3 * 102

m is called mantissa, b is the basis and e the exponent. The basis isn't necessarily the same as the basis of the number system. You can write:

 1228.8 = 2.4 * 83     b = 8, e = 3, m = 2.4

You can see, that the floating-point representation gives you big liberties on how to represent a number. To avoid a chaos a standard was introduced: IEEE 754. .NET - and thus Delphi Prism - uses this standard.

The standard defines, that the basis is 2. In the next step the memory of a 32 bit (64 bit) floating-point number is partitioned in the following way:

  1. 1 bit for the number's sign
  2. 8 bits (11 bits) for storing the exponent. The exponent is written as d - 127 (d - 1023) on only the always positive d is stored. Thus you don't need memory to store d's sign, too.
  3. 23 bits (52 bits) are used for the mantissa. In normal representation the mantissa is of the form 1.f and only f is stored.
  4. In sub-normal representation, which is used to represent very small numbers with high precision, the following rules apply
    1. The exponent is supposed to be -126, so you don't need memory for that
    2. 1 bit for the sign
    3. The remaining bits are used for the mantissa. It's assumed to be in the form 0.f and only f is stored.
  5. To represent the numbers positive infinity or negative infinity, the sign is set accordingly, the mantisssa is set to zero and the exponent to 255 (2047).
  6. To represent "Not a Number" (NaN), the sign is set to an arbitrary value, the exponent to 255 (2047) and the value of the mantissa to a value greater than zero.

Calculator vs. Comma

To get some practice into the crash course, we'll now extend the calculator sample to work with rational numbers. Currently it uses Integer to store numbers. We can use the types Single or Double instead. Single is 32 bit long and therefore is very fast on 32bit operating systems. It's good enough for many applications. Double offers twice the precision, but is 64 bit long. You'll probably want to use this one for scientific applications.

We'll use the Double type for the calculator sample. Thanks to type inference we don't have to change much. Like the Integer type the Double type offers a Parse (and TryParse) method, which can be uses in the exact same way. (The same's true for Single.)

The only thing to do, is edit the click handlers for adding and dividing numbers and replace every "Integer" by a "Double". There should be four occurences in total. After that reading the numbers should look like this:

var firstNumber := Double.Parse(tbFirstNumber.Text);

Everything else stays the same.

Now you can test the calculator sample with "comma numbers". If you like, you can extend the calcutor with a "subtract" and "mulitply" feature, but we're finished with it as far as this crash course is concerned.

Casts

You can convert numbers from one data type to another. You can convert a Single into a Double, and (with some restrictions) vice versa. You call this conversion a cast.

There're implicit and explicit casts. An implicit cast is done by the compiler without the programmer get involved in it. Sometimes he does not even notice it. That's fine if a smaller type (like Single) is converted into a bigger type (like Double), because then the information is completely preserved.

An explicit cast is a cast "forced" by the programmer. For example when assigning an integer to a boolean, the compiler won't allow it without an explicit cast:

var b : Boolean := 100000;

You'll get an error message: "(CE15) Type mismatch, cannot assign System.Int32 to System.Boolean". You can force the compiler to do this by using an explicit cast:

var b : Boolean := Boolean(100000);

Note that in .NET even with an explicit cast you cannot convert every type in an arbitrary other type. You cannot convert a String into a Boolean for example.

Overflows

Be carefull with implicit casts, they sometimes lead to surprising results:

var a := 100000;
var b : Int16 := a;

MessageBox.Show(b.ToString);

This will show "-31072". To explain this, we only have to look at the number range an Int16 can hold: -32768 .. 32767. Therefore a with a value of 100000 does not fit in b. What happens is, that <bb>b</tt> is "filled up" until 32767. Then there's an overflow and it starts at -32768. It's again filled up until 32767 and starts again at -32768. Now there're only 1696 of a "remaining", so conversion stops at -31072.

The compiler does not warn you about that, so you have to be carefull which variable you assign to which other variable.


See Also

The Prism Primer: Part 1Part 2Part 3Part 4Part 5Part 6Part 7Part 8Part 9


Oxygene-48.png

Oxygene

GlossariesKeywordsTypesFAQHow To

Navigation
Areas
More
Toolbox