Variables of the Decimal type are stored internally as integers in 16 bytes and are scaled by a power of 10. The scaling power determines the number of decimal digits to the right of the floating point, and it’s an integer value from 0 to 28. When the scaling power is 0, the value is multiplied by 100, or 1, and it’s represented without decimal digits. When the scaling power is 28, the value is divided by 1028 (which is 1 followed by 28 zeros — an enormous value), and it’s represented with 28 decimal digits.

The largest possible value you can represent with a Decimal value is an integer: 79,228,162, 514,264,337,593,543,950,335. The smallest number you can represent with a Decimal variable is the negative of the same value. These values use a scaling factor of 0. When the scaling factor is 28, the largest value you can represent with a Decimal variable is quite small, actually. It’s 7.9228162514264337593543950335 (and the smallest value is the same with a minus sign). This is a very small numeric value (not quite 8), but it’s represented with extreme accuracy. The number zero can’t be represented precisely with a Decimal variable scaled by a factor of 28.

The smallest positive value you can represent with the same scaling factor is 0.00. . .01 (there are 27 zeros between the decimal period and the digit 1) — an extremely small value, but still not quite zero. The more accuracy you want to achieve with a Decimal variable, the smaller the range of available values you have at your disposal — just as with everything else in life.

When using decimal numbers, the compiler keeps track of the decimal digits (the digits following the decimal point) and treats all values as integers. The value 235.85 is represented as the integer 23585, but the compiler knows that it must scale down the value by 100 when it finishes using it. Scaling down by 100 (that is, 102) corresponds to shifting the decimal point by two places. First, the compiler multiplies this value by 100 to make it an integer. Then, it divides it by 100 to restore the original value. Let’s say that you want to multiply the following values:

1 | 328.558 * 12.4051 |

First, you must turn them into integers. You must remember that the first number has three decimal digits, and the second number has four decimal digits. The result of the multiplication will have seven decimal digits. So you can multiply the following integer values:

1 | 328558 * 124051 |

and then treat the last seven digits of the result as decimals. Use the Windows Calculator (in the Scientific view) to calculate the previous product. The result is 40,757,948,458. The actual value after taking into consideration the decimal digits is 4,075.7948458. This is how the compiler manipulates the Decimal data type. Insert the following lines in a button’s Click event handler and execute the program:

1 2 3 4 5 | Dim a As Decimal = 328.558D Dim b As Decimal = 12.4051D Dim c As Decimal c = a * b Debug.WriteLine(c.ToString) |

The D character at the end of the two numeric values specifies that the numbers should be converted into Decimal values. By default, every value with a fractional part is treated as a Double value. Assigning a Double value to a Decimal variable will produce an error if the Strict option is on, so we must specify explicitly that the two values should be converted to the Decimal type. The D character at the end of the value is called a type character. Table 2.2 lists all of them.

If you perform the same calculations with Single variables, the result will be truncated (and rounded) to three decimal digits: 4,075.795. Notice that the Decimal data type didn’t introduce any rounding errors. It’s capable of representing the result with the exact number of decimal digits. This is the real advantage of Decimals, which makes them ideal for financial applications. For scientific calculations, you must still use Doubles. Decimal numbers are the best choice for calculations that require a specific precision (such as four or eight decimal digits).