# Fixed-point types

## Decimal fixed-point types

We have already seen how to specify floating-point types. However, in some applications floating-point is not appropriate since, for example, the roundoff error from binary arithmetic may be unacceptable or perhaps the hardware does not support floating-point instructions. Ada provides a category of types, the decimal fixed-point types, that allows the programmer to specify the required decimal precision (number of digits) as well as the scaling factor (a power of ten) and, optionally, a range. In effect the values will be represented as integers implicitly scaled by the specified power of 10. This is useful, for example, for financial applications.

The syntax for a simple decimal fixed-point type is

```
type <type-name> is delta <delta-value> digits <digits-value>;
```

In this case, the `delta`

and the `digits`

will be used by the
compiler to derive a range.

Several attributes are useful for dealing with decimal types:

Attribute Name |
Meaning |
---|---|

First |
The first value of the type |

Last |
The last value of the type |

Delta |
The delta value of the type |

In the example below, we declare two data types: `T3_D3`

and `T6_D3`

.
For both types, the delta value is the same: 0.001.

When running the application, we see that the delta value of both
types is indeed the same: 0.001. However, because `T3_D3`

is restricted
to 3 digits, its range is -0.999 to 0.999. For the `T6_D3`

, we have
defined a precision of 6 digits, so the range is -999.999 to 999.999.

Similar to the type definition using the `range`

syntax, because we
have an implicit range, the compiled code will check that the variables
contain values that are not out-of-range. Also, if the result of a
multiplication or division on decimal fixed-point types is smaller than
the delta value required for the context, the actual result will be
zero. For example:

In this example, the result of the operation 0.001 * 0.5 is
0.0005. Since this value is not representable for the `T3_D3`

type
because the delta value is 0.001, the actual value stored in variable
`A`

is zero. However, accuracy is preserved during the arithmetic
operations if the target has sufficient precision, and the value
displayed for C is 0.000500.

## Ordinary fixed-point types

Ordinary fixed-point types are similar to decimal fixed-point types in that the
values are, in effect, scaled integers. The difference between them is in the
scale factor: for a decimal fixed-point type, the scaling, given explicitly by
the type's `delta`

, is always a power of ten.

In contrast, for an ordinary fixed-point type, the scaling is defined by the
type's `small`

, which is derived from the specified `delta`

and, by
default, is a power of two. Therefore, ordinary fixed-point types are sometimes
called binary fixed-point types.

Note

Ordinary fixed-point types can be thought of being closer to the actual representation on the machine, since hardware support for decimal fixed-point arithmetic is not widespread (rescalings by a power of ten), while ordinary fixed-point types make use of the available integer shift instructions.

The syntax for an ordinary fixed-point type is

```
type <type-name> is
delta <delta-value>
range <lower-bound> .. <upper-bound>;
```

By default the compiler will choose a scale factor, or `small`

, that is a
power of 2 no greater than <delta-value>.

For example, we may define a normalized range between -1.0 and 1.0 as following:

In this example, we are defining a 32-bit fixed-point data type for our normalized range. When running the application, we notice that the upper bound is close to one, but not exact one. This is a typical effect of fixed-point data types — you can find more details in this discussion about the Q format. We may also rewrite this code with an exact type definition:

We may also use any other range. For example:

In this example, we are defining a 16-bit type called `T_Inv_Trig`

,
which has a range from -π/2 to π/2.

All standard operations are available for fixed-point types. For example:

As expected, `R`

contains 0.75 after the addition of `A`

and `B`

.

In fact the language is more general than these examples imply, since in practice it is typical to need to multiply or divide values from different fixed-point types, and obtain a result that may be of a third fixed-point type. The details are outside the scope of this introductory course.

It is also worth noting, although again the details are outside the scope of
this course, that you can explicitly specify a value for an ordinary
fixed-point type's `small`

. This allows non-binary scaling, for example:

```
type Angle is
delta 1.0/3600.0
range 0.0 .. 360.0 - 1.0 / 3600.0;
for Angle'Small use Angle'Delta;
```