# Ada Programming/Mathematical calculations


Ada is very well suited for all kinds of calculations. You can define
your own fixed point and floating point types and --- with the aid of
generic packages call all the mathematical functions you need. In that
respect Ada is on par with Fortran.
This module will show you how to use them and while we progress we
create a simple RPN
calculator.

## Simple calculations

### Addition

Additions can be done using the predefined operator
. The operator is predefined for all
numeric types and the following, working code, demonstrates its use:

\
\
`{{Ada/--|{{Ada/95/RM|A|10|1|title=The Package Text_IO}}}}`{=mediawiki}\
` ``;`\
\
` Numeric_1 `\
`   `` Value_Type `` `` 12`\
`         `` -999_999_999_999.0e999 .. 999_999_999_999.0e999;`\
\
`   `` T_IO `` Ada.Text_IO;`\
`   `` F_IO `` ``  Ada.Text_IO.Float_IO (Value_Type);`\
\
`   Value_1 : Value_Type;`\
`   Value_2 : Value_Type;`\
\
\
`   T_IO.Put ("First Value : ");`\
`   F_IO.Get (Value_1);`\
`   T_IO.Put ("Second Value : ");`\
`   F_IO.Get (Value_2);`\
\
`   F_IO.Put (Value_1);`\
`   T_IO.Put (" + ");`\
`   F_IO.Put (Value_2);`\
`   T_IO.Put (" = ");`\
`   F_IO.Put (Value_1 `` Value_2);`\
` Numeric_1;`

### Subtraction

Subtractions can be done using the predefined operator
. The following extended demo shows the
use of + and - operator together:

\
\
`{{Ada/--|{{Ada/95/RM|A|10|1|title=The Package Text_IO}}}}`{=mediawiki}\
` `\
\
` Numeric_2`\
\
`  `` Value_Type`\
`  `` `\
`     12`\
`  `\
`     -999_999_999_999.0e999 .. 999_999_999_999.0e999;`\
\
`  `` T_IO `` ``;`\
`  `` F_IO `` ``  Ada.Text_IO.Float_IO (Value_Type);`\
\
`  Value_1   : Value_Type;`\
`  Value_2   : Value_Type;`\
`  Result    : Value_Type;`\
`  Operation : Character;`\
\
\
`  T_IO.Put ("First Value  : ");`\
`  F_IO.Get (Value_1);`\
`  T_IO.Put ("Second Value : ");`\
`  F_IO.Get (Value_2);`\
`  T_IO.Put ("Operation    : ");`\
`  T_IO.Get (Operation);`\
\
`  `` Operation `\
`     `` '+' =>`\
`        Result := Value_1 + Value_2;`\
`     `` '-' =>`\
`        Result := Value_1 - Value_2;`\
`     `` `` =>`\
`        T_IO.Put_Line ("Illegal Operation.");`\
`        `` Exit_Numeric_2;`\
`  `` ``;`\
\
`  F_IO.Put (Value_1);`\
`  T_IO.Put (" ");`\
`  T_IO.Put (Operation);`\
`  T_IO.Put (" ");`\
`  F_IO.Put (Value_2);`\
`  T_IO.Put (" = ");`\
`  F_IO.Put (Result);`\
\
`Exit_Numeric_2`\
`  ``;`\
\
` Numeric_2;`

Purists might be surprised about the use of goto --- but some people
prefer the use of goto over the use of multiple return statements if
inside functions --- given that, the opinions on this topic vary
strongly. See the isn\'t goto
evil article.

### Multiplication

Multiplication can be done using the predefined operator
. For a demo see the next chapter about
Division.

### Division "wikilink")

Divisions can be done using the predefined operators
, ,
. The operator
 performs a normal division,
 returns a modulus division and
 returns the remainder of the modulus
division.

The following extended demo shows the use of the
, ,
 and 
operators together as well as the use of a four number wide stack to
store intermediate results:

The operators  and
 are not part of the demonstration as
they are only defined for integer types.

\
\
` ``;`\
\
` Numeric_3 `\
`   `` Pop_Value;`\
`   `` Push_Value;`\
\
`   `` Value_Type `` `` 12 `\
`     -999_999_999_999.0e999 .. 999_999_999_999.0e999;`\
\
`   `` Value_Array `` `` (Natural `` 1 .. 4) `` Value_Type;`\
\
`   `` T_IO `` Ada.Text_IO;`\
`   `` F_IO `` `` Ada.Text_IO.Float_IO (Value_Type);`\
\
`   Values    : Value_Array := (`` => 0.0);`\
`   Operation : String (1 .. 40);`\
`   Last      : Natural;`\
\
`   `` Pop_Value `\
`   `\
`      Values (Values'`` + 1 .. Values'``) :=`\
`        Values (Values'`` + 2 .. Values'``) & 0.0;`\
`   `` Pop_Value;`\
\
`   `` Push_Value `\
`   `\
`      Values (Values'`` + 1 .. Values'``) :=`\
`        Values (Values'`` .. Values'`` - 1);`\
`   `` Push_Value;`\
\
\
`   Main_Loop:`\
`   `\
`      T_IO.Put (">");`\
`      T_IO.Get_Line (Operation, Last);`\
\
`      `` Last = 1 `` `` Operation (1) = '+' `\
`         Values (1) := Values (1) + Values (2);`\
`         Pop_Value;`\
`      `` Last = 1 `` `` Operation (1) = '-' `\
`         Values (1) := Values (1) + Values (2);`\
`         Pop_Value;`\
`      `` Last = 1 `` `` Operation (1) = '*' `\
`         Values (1) := Values (1) * Values (2);`\
`         Pop_Value;`\
`      `` Last = 1 `` `` Operation (1) = '/' `\
`         Values (1) := Values (1) / Values (2);`\
`         Pop_Value;`\
`      `` Last = 4 `` `` Operation (1 .. 4) = "exit" `\
`         `` Main_Loop;`\
`      `\
`         Push_Value;`\
`         F_IO.Get (From => Operation, Item => Values (1), Last => Last);`\
`      `` ``;`\
`      `\
`      Display_Loop:`\
`      `` I `` `` Value_Array'`` `\
`         F_IO.Put`\
`           (Item => Values (I),`\
`            Fore => F_IO.Default_Fore,`\
`            Aft  => F_IO.Default_Aft,`\
`            Exp  => 4);`\
`         T_IO.New_Line;`\
`      `` `` Display_Loop;`\
`   `` `` Main_Loop;`\
\
`   ``;`\
` Numeric_3;`

## Exponential calculations

All exponential functions are defined inside the generic package
.

### Power of

Calculation of the form $x^y$ are performed by the operator
. Beware: There are two versions of
this operator. The predefined operator 
allows only for Standard.Integer to be used as exponent. If you need to
use a floating point type as exponent you need to use the
 defined in
.

### Root "wikilink")

The square root $\sqrt{x}$ is calculated with the function `Sqrt()`.
There is no function defined to calculate an arbitrary root
$\sqrt[n]{x}$. However you can use logarithms to calculate an arbitrary
root using the mathematical identity: $\sqrt[b]{a} = e^{\log_e (a) / b}$
which will become `root := Exp (Log (a) / b)` in Ada. Alternatively, use
$\sqrt[b]{a}=a^{\frac1b}$ which, in Ada, is `root := a**(1.0/b)`.

### Logarithm

defines a function for both the arbitrary logarithm $log_n(x)$ and the
natural logarithm $log_e(x)$, both of which have the same name `Log()`
distinguished by the number of parameters.

### Demonstration

The following extended demo shows the how to use the exponential
functions in Ada. The new demo also uses
Unbounded_String
instead of Strings which make the comparisons easier.

Please note that from now on we won\'t copy the full sources any more.
Do follow the download links to see the full program.

\
\
` ``;`\
` ``;`\
` ``;`\
\
` Numeric_4 `\
`  `` Str `` Ada.Strings.Unbounded;`\
`  `` T_IO `` Ada.Text_IO;`\
\
`  `` Pop_Value;`\
`  `` Push_Value;`\
`  `` Get_Line `` Str.Unbounded_String;`\
\
`  `` Value_Type `` `` 12 `\
`     -999_999_999_999.0e999 .. 999_999_999_999.0e999;`\
\
`  `` Value_Array `` `` (Natural `` 1 .. 4) `` Value_Type;`\
\
`  `` F_IO `` `` Ada.Text_IO.Float_IO (Value_Type);`\
`  `` Value_Functions `` `` Ada.Numerics.Generic_Elementary_Functions (`\
`     Value_Type);`\
\
`  `` Value_Functions;`\
`  `` `` Str.Unbounded_String;`\
\
`  Values    : Value_Array := (`` => 0.0);`\
`  Operation : Str.Unbounded_String;`\
`  Dummy     : Natural;`\
\
`  `` Get_Line `` Str.Unbounded_String `\
`     BufferSize : `` := 2000;`\
`     Retval     : Str.Unbounded_String := Str.Null_Unbounded_String;`\
`     Item       : String (1 .. BufferSize);`\
`     Last       : Natural;`\
`  `\
`     Get_Whole_Line :`\
`        `\
`           T_IO.Get_Line (Item => Item, Last => Last);`\
\
`           Str.Append (Source => Retval, New_Item => Item (1 .. Last));`\
\
`           `` Get_Whole_Line `` Last < Item'``;`\
`        `` `` Get_Whole_Line;`\
\
`     `` Retval;`\
`  `` Get_Line;`\
\
`...`\
\
\
`  Main_Loop :`\
`     `\
`        T_IO.Put (">");`\
`        Operation := Get_Line;`\
\
`...`\
`        `` Operation = "e" `` `\
`           Push_Value;`\
`           Values (1) := Ada.Numerics.e;`\
`        `` Operation = "**" `` `` Operation = "^" `` `\
`           Values (1) := Values (1) ** Values (2);`\
`           Pop_Value;`\
`        `` Operation = "sqr" `` `\
`           Values (1) := Sqrt (Values (1));`\
`        `` Operation = "root" `` `\
`           Values (1) :=`\
`              Exp (Log (Values (2)) / Values (1));`\
`           Pop_Value;`\
`        `` Operation = "ln" `` `\
`           Values (1) := Log (Values (1));`\
`        `` Operation = "log" `` `\
`           Values (1) :=`\
`              Log (Base => Values (1), X => Values (2));`\
`           Pop_Value;`\
`        `` Operation = "``" `\
`           `` Main_Loop;`\
`        `\
`           Push_Value;`\
`           F_IO.Get`\
`             (From => Str.To_String (Operation),`\
`              Item => Values (1),`\
`              Last => Dummy);`\
`        `` ``;`\
\
`...`\
`     `` `` Main_Loop;`\
\
`  ``;`\
` Numeric_4;`

## Higher math

### Trigonometric calculations

The full set of trigonometric functions are
defined inside the generic package
.
All functions are defined for 2π and an arbitrary cycle value (a full
cycle of revolution).

Please note the difference of calling the `Arctan ()` function.

` ``;`\
` ``;`\
` ``;`\
\
` Numeric_5 `\
\
`...`\
\
`  `` Put_Line (Value : `` Value_Type);`\
\
`  `` Value_Functions;`\
`  `` `` Str.Unbounded_String;`\
\
`  Values    : Value_Array := (`` => 0.0);`\
`  Cycle     : Value_Type  := Ada.Numerics.Pi;`\
`  Operation : Str.Unbounded_String;`\
`  Dummy     : Natural;`\
\
`...`\
\
`  `` Put_Line (Value : `` Value_Type) `\
`  `\
`     `` `` Value_Type'`` (Value) >=`\
`        `` Value_Type'`` (10.0 ** F_IO.Default_Aft)`\
`     `\
`        F_IO.Put`\
`          (Item => Value,`\
`           Fore => F_IO.Default_Aft,`\
`           Aft  => F_IO.Default_Aft,`\
`           Exp  => 4);`\
`     `\
`        F_IO.Put`\
`          (Item => Value,`\
`           Fore => F_IO.Default_Aft,`\
`           Aft  => F_IO.Default_Aft,`\
`           Exp  => 0);`\
`     `` ``;`\
`     T_IO.New_Line;`\
\
`     ``;`\
`  `` Put_Line;`\
\
`...`\
\
\
`  Main_Loop :`\
`     `\
`        Display_Loop :`\
`           `` I `` ``  Value_Array'`` `\
`              Put_Line (Values (I));`\
`           `` `` Display_Loop;`\
`        T_IO.Put (">");`\
`        Operation := Get_Line;`\
\
`...`\
`        `` Operation = "deg" `` `\
`           Cycle := 360.0;`\
`        `` Operation = "rad" `` `\
`           Cycle := Ada.Numerics.Pi;`\
`        `` Operation = "grad" `` `\
`           Cycle := 400.0;`\
`        `` Operation = "pi" `` `` Operation = "π" `` `\
`           Push_Value;`\
`           Values (1) := Ada.Numerics.Pi;`\
`        `` Operation = "sin" `` `\
`           Values (1) := Sin (X => Values (1), Cycle => Cycle);`\
`        `` Operation = "cos" `` `\
`           Values (1) := Cos (X => Values (1), Cycle => Cycle);`\
`        `` Operation = "tan" `` `\
`           Values (1) := Tan (X => Values (1), Cycle => Cycle);`\
`        `` Operation = "cot" `` `\
`           Values (1) := Cot (X => Values (1), Cycle => Cycle);`\
`        `` Operation = "asin" `` `\
`           Values (1) := Arcsin (X => Values (1), Cycle => Cycle);`\
`        `` Operation = "acos" `` `\
`           Values (1) := Arccos (X => Values (1), Cycle => Cycle);`\
`        `` Operation = "atan" `` `\
`           Values (1) := Arctan (Y => Values (1), Cycle => Cycle);`\
`        `` Operation = "acot" `` `\
`           Values (1) := Arccot (X => Values (1), Cycle => Cycle);`\
\
`...`\
`     `` `` Main_Loop;`\
\
`  ``;`\
` Numeric_5;`

The Demo also contains an improved numeric output which behaves more
like a normal calculator.

### Hyperbolic calculations

You guessed it: The full set of hyperbolic functions is defined inside
the generic package
.



` ``;`\
` ``;`\
` ``;`\
` ``;`\
\
` Numeric_6 `\
`  `` Str `` Ada.Strings.Unbounded;`\
`  `` T_IO `` Ada.Text_IO;`\
`  `` Exept `` Ada.Exceptions;`\
\
`...`\
\
` `\
`  Main_Loop :`\
`     `\
`        Try :`\
`           `\
`              Display_Loop :`\
`...`\
`              `` Operation = "sinh" `` `\
`                 Values (1) := Sinh (Values (1));`\
`              `` Operation = "cosh" `` `\
`                 Values (1) := Coth (Values (1));`\
`              `` Operation = "tanh" `` `\
`                 Values (1) := Tanh (Values (1));`\
`              `` Operation = "coth" `` `\
`                 Values (1) := Coth (Values (1));`\
`              `` Operation = "asinh" `` `\
`                 Values (1) := Arcsinh (Values (1));`\
`              `` Operation = "acosh" `` `\
`                 Values (1) := Arccosh (Values (1));`\
`              `` Operation = "atanh" `` `\
`                 Values (1) := Arctanh (Values (1));`\
`              `` Operation = "acoth" `` `\
`                 Values (1) := Arccoth (Values (1));`\
`...`\
`           `\
`              `` An_Exception : `` =>`\
`                 T_IO.Put_Line`\
`                   (Exept.Exception_Information (An_Exception));`\
`           `` Try;`\
`     `` `` Main_Loop;`\
\
`  ``;`\
` Numeric_6;`

As added bonus this version supports error handling and therefore won\'t
just crash when an illegal calculation is performed.

### Complex arithmethic

For complex arithmetic Ada
provides the package
. This
package is part of the \"special need Annexes\" which means it is
optional. The open source Ada compiler GNAT implements all \"special
need Annexes\" and therefore has complex arithmetic available.

Since Ada supports user defined operators, all
`<small>`{=html}(,
,
)`</small>`{=html} operators have their
usual meaning as soon as the package
 has
been instantiated `<small>`{=html}( \...
 
\...)`</small>`{=html} and the type has been made visible
`<small>`{=html}(
 \...)`</small>`{=html}

Ada also provides the packages
 and

which provide similar functionality to their normal counterparts. But
there are some differences:

-       supports only the exponential and trigonometric functions which make
    sense in complex arithmetic.

```{=html}
<!-- -->
```
-       is a child package of  and
    therefore needs its own . Note: the
    `Get ()`
    function is pretty fault tolerant - if you forget the \",\" or the
    \"()\" pair it will still parse the input correctly.

So, with only a very few modifications you can convert your \"normals\"
calculator to a calculator for complex arithmetic:

` Ada.Text_IO.Complex_IO;`\
` Ada.Numerics.Generic_Complex_Types;`\
` Ada.Numerics.Generic_Complex_Elementary_Functions;`\
` Ada.Strings.Unbounded;`\
` Ada.Exceptions; `\
\
` Numeric_7 `\
\
`...`\
` `\
`  `` Complex_Types `` `` Ada.Numerics.Generic_Complex_Types (`\
`     Value_Type);`\
`  `` Complex_Functions `` `\
`     Ada.Numerics.Generic_Complex_Elementary_Functions (`\
`     Complex_Types);`\
`  `` C_IO `` `` Ada.Text_IO.Complex_IO (Complex_Types);`\
\
`  `` Value_Array `\
`     `` (Natural `` 1 .. 4) `` Complex_Types.Complex;`\
\
`  `` Put_Line (Value : `` Complex_Types.Complex);`\
\
`  `` `` Complex_Types.Complex;`\
`  `` `` Str.Unbounded_String;`\
`  `` Complex_Functions;`\
\
`  Values    : Value_Array :=`\
`     (`` => Complex_Types.Complex'(Re => 0.0, Im => 0.0));`\
\
`...`\
` `\
`  `` Put_Line (Value : `` Complex_Types.Complex) `\
`  `\
`     `` (`` Value_Type'`` (Value.Re) >=`\
`         `` Value_Type'`` (10.0 ** C_IO.Default_Aft))`\
`       `` `` (`` Value_Type'`` (Value.Im) >=`\
`                `` Value_Type'`` (10.0 ** C_IO.Default_Aft))`\
`     `\
`        C_IO.Put`\
`          (Item => Value,`\
`           Fore => C_IO.Default_Aft,`\
`           Aft  => C_IO.Default_Aft,`\
`           Exp  => 4);`\
`     `\
`        C_IO.Put`\
`          (Item => Value,`\
`           Fore => C_IO.Default_Aft,`\
`           Aft  => C_IO.Default_Aft,`\
`           Exp  => 0);`\
`     `` ``;`\
`     T_IO.New_Line;`\
\
`     ``;`\
`  `` Put_Line;`\
\
\
\
`...`\
`              `` Operation = "e" `` `\
`                 Push_Value;`\
`                 Values (1) :=`\
`                    Complex_Types.Complex'(Re => Ada.Numerics.e, Im => 0.0);`\
\
`...`\
\
`              `` Operation = "pi" `` `` Operation = "π" `` `\
`                 Push_Value;`\
`                 Values (1) :=`\
`                    Complex_Types.Complex'(Re => Ada.Numerics.Pi, Im => 0.0);`\
`              `` Operation = "sin" `` `\
`                 Values (1) := Sin (Values (1));`\
`              `` Operation = "cos" `` `\
`                 Values (1) := Cot (Values (1));`\
`              `` Operation = "tan" `` `\
`                 Values (1) := Tan (Values (1));`\
`              `` Operation = "cot" `` `\
`                 Values (1) := Cot (Values (1));`\
`              `` Operation = "asin" `` `\
`                 Values (1) := Arcsin (Values (1));`\
`              `` Operation = "acos" `` `\
`                 Values (1) := Arccos (Values (1));`\
`              `` Operation = "atan" `` `\
`                 Values (1) := Arctan (Values (1));`\
`              `` Operation = "acot" `` `\
`                 Values (1) := Arccot (Values (1));`\
\
`...`\
\
`  ``;`\
` Numeric_7;`

### Vector and Matrix Arithmetic

Ada supports vector and
matrix
Arithmetic for both normal real types and complex types. For those, the
generic packages Ada.Numerics.Generic_Real_Arrays and
Ada.Numerics.Generic_Complex_Arrays are used. Both packages offer the
usual set of operations, however there is no I/O package and
understandably, no package for elementary functions.

Since there is no I/O package for vector and matrix I/O creating a demo
is by far more complex --- and hence not ready yet. You can have a look
at the current progress which will be a universal calculator merging all
feature.

Status: Stalled - for a Vector and Matrix stack we need
Indefinite_Vectors --- which are currently not part of GNAT/Pro. Well I
could use the booch components \...

## See also

### Wikibook

-   Ada Programming
-   Ada
    Programming/Delimiters/-
-   Ada Programming/Libraries/Ada.Numerics.Generic Complex
    Types
-   Ada Programming/Libraries/Ada.Numerics.Generic Elementary
    Functions

### Ada 95 Reference Manual

-   
-   
-   
-   
-   
### Ada 2005 Reference Manual

-   
-   
-   
-   
-   
