Ada for Mathematics

Ada shines on Modeling.

One of the best features of Ada is how it can adapt to many different real life and mathematical models.

Here we are going to explore some of it's capacities.

The problems of Computing Maths... in other languages

One of the most frustrating things you have to deal in programming is the lack of a nice numeric system that adapts to what we need.

Usually you have to deal with Inverted-Complement-2-16(32?)Bits Binary Numbers for Integers, and unsigned overrides of the same type for Naturals. These are predefined in the operating system, and most of the time we don't have control over what they are.

This isn't much of a problem, but it doesn't allow to work with sets of numbers that are equivalent to a Natural set, but are not formatted as naturals. As an example, money (in Europe) is a Integer set with a unit of cents, but we work with Euros. We either have to choose cents as our unit (potentially confusing as in "withdraw(1000)" is 10€) or use floats, and have extra decimals that we are not really that interested on having.

And don't even get me started on all the problems a Float type can produce. For starters the density of the set is inverse to it's value (which means answers are just approximations) and comparing two numbers is never going to be what you expect.

So, the point: Programming Maths is a nightmare, and the results always have to be taken with a grain of salt.

Personal Opinion PS: Somehow this feel intentional. Informatics shielded themselves from other sciences and engineers since the 80's, and made a very transversal discipline a Private (Boys) Club. Thankfully, tools like Python are changing that trend nowadays.

Numeric Types

Integer Types

But here comes Ada to save the day.

In Ada there exist a wide and delightful variety of numeric types. Not only that, but you can set your own very easily.

For starters, we have a simple Integer type. It works as you would expect: A set of Integer numbers. The only issue you will (barely) encounter is that it has to be limited for the computer to handle.

But this is unavoidable in any computer language.

type Integer
type Integer is range Integer'First .. Integer'Last;

This range depends on the system. In 16-bit computers is around -32.000 to 32.000, and in 32-bit computers approximately ± 2.000.000.000.

Is worth mentioning that there are two subsets of Integer defined in the language.

Natural, which is defined from 0 to Integer'Last

type Natural; --is range 0 .. Integer'Last;

And Positive, defined from 1 to Integer'Last.

type Positive; --is range 1 .. Integer'Last;

As easy as it seems, we can define our own subsets of Integers to represent any quantity with whole numbers. In adition, this saves memory and processing power for the computer.

type Drivers_Age is range 18 .. 99;
type hour is range 0 .. 24;
type dice is range 1 .. 6;

Real Numbers

It should come with no surprise that a complete representation of the Real Set is not possible in a computer.

Or in real life, for that matter.

But Ada can cover all ranges of numeric utilities with different types that should come in handy when working with numbers that stand for the Real Set.

They are as good as you can get when modelling mathematics, guys. Don't be picky!

The Decimal Types

It may come as a surprise that you can define a type as a multiple of 10-n with an arbitrary n.

It is definitely not a common feature in programming languages.

type <Name> is delta <Precision> digits <Length>; 
type <Name> is delta <Precision> range <Range>; 
type Withdraws_Euros is delta 10**(-2) digits 6; 
  --We limit the Withdraws to 1_000.00€ 
type Measured_Voltage is delta 0.001 digits 5; --0.0 to 99.999
type Voltmeter is delta 0.001 range -20.0 .. 20.0;

The Floating Types

Ada also allows for floating point types for numbers, as many other languages. This type, as established, can be problematic at a times, but is a simple type in memory, and behaves in parallel manner to Real numbers.

Coefficient : float range -1.0 .. 1.0;
electron_charge : Constant Float := 1.601E-19;
speed_of_light: Constant float := 2.998E8;

Float is composed of two elements. Mantissa and exponent. Therefor, the precission is

Modular Numbers

For numbers that repeat on cycles

Ada has modular arithmetics already incorporated

type <name> is mod <base>
type minute is mod 60;

In this example the valid values are 0 to 59, and then it wraps.

Writing and reading Numbers

To communicate with the Text_IO Library we should be aware of the integrated methods for the type that convert Numbers on string and strings on numbers:

  • I : Integer := Integer'Value("613");
  • S : String := Integer'Image(613);

These allow communicating with the Put / Get processes of the Text_IO library, but there also exist some specific libraries for specific types.

Integer_Text_IO

Type conversion

To change from real types to Integers we can use the type casting system.

Is very simple, you just write the intended type and as parameter the variable or value, and it rounds to the value in the expected type.

<type>(<var>)
Integer(3.14);  --  3
Integer(2.95);  --  3
float(4);       --  4.0

Numeric Literals

I'm going to get weird for a second here, skip to 😴 if you want to skip to conclusions.

You may have noticed something weird. Almost metaphysical.

If I am defining the type on the left, what type is the symbol I'm using on the right? When I give the variable integer "N" the value "3", what type is that three?

That's actually an interesting question. The compiler has a "build in meta-function" called a Literal expression that returns that value on the objective type. That means, when I call 3 I'm actually calling the function 3 (whatever that is) and due to generic programs (that build the types on the run) you get what you'd expect.

😴 Sleeping yet? Well, this means that we have arbitrary numbers built in Ada. Real real numbers (for real).

<value>  

3   --  Returns a 3 value in any integer-like type
3.0 --  Returns a 3 value in any pointed type
3_000  -- 3000 with a beautifier separator
300_0  -- Still 3000, with an awkward separator
300.0  -- 300 as a fix/float point type
3_00.0 -- Same, but with a separator
0300   -- Integer 300 with a leading zero
0300.0 -- Float 300 with leading zero
3E3    --  3000 in exponent notation
3e3    --  3000 in exponent base 10, not Euler!
3E+3   --  3000 
3.1E3  --  3100
3.1E-3 --  0.0031

You can also change the base of the literals. Any base from 2 to 16.

"Wait whaaaaat?! That's awesome! " should be a proper reaction to this information.

<base>#<value>  

4#30#   --  12, integer-like type
2#101.1# -- 5.5, point type, in Binary
16#FFF_000#  -- FFF000 In base 16, or hexadecimal
7#1#E2    --  49 in exponent notation
          --  1 *  7**2  
2#1.0#e-1 --  1/2 in exponent float base 2, not Euler!

16#CAFE#  --  51966  So you notice the context, 
          --  of the E specially, to give meaning to symbols

16#0FFF#               -- Same Thing
2#0000_1111_1111_1111# -- As this