2. Numbers

Checking Whether a String Is a Valid Number

   begin
      Int := Integer'Value(Numeric_String);
   exception
      when Constraint_Error =>
         Put_Line(Numeric_String & " is not an Integer");
   end;
   begin
      Flt := Float'Value(Numeric_String);
   exception
      when Constraint_Error =>
         Put_Line(Numeric_String & " is not a float");
   end;

-- Ada also allows you to define your own numeric types and check
-- for valid conversion from a string, including out of range
-- errors
   begin
      Small := Small_Int'Value(Numeric_String);
   exception
      when Constraint_Error =>
         Put_Line(Numeric_String & " is not a Small_Int");
   end;

Comparing Floating-Point Numbers

function equal(Num1, Num2 : Float; Accuracy : Integer) return Boolean is
   My_Delta : Float := 10.0 ** (-Accuracy);
   Diff     : Float := abs (Num1 - Num2);
begin
   return Diff < My_Delta;
end equal;
----------------------------------------------------------------------
-- Ada offers another form of Real numbers : Fixed point types
-- You specify the fixed precision of the type in the "delta"
-- parameter for the type
-- The following type will have a clearly specified range:
-- -999_999_999.999 to 999_999_999.999

type Real is delta 0.001 digits 12;

R1, R2 : Real;
-- [...]
if R1 = R2 then
   Ada.Text_Io.Put_Line (Real'Image(R1) & " equals"
                       & Real'Image(R2));
end if;

wage : Float := 5.36;
week : Float := 40.0 * wage;
begin
   Put("One week's wage is: $");
   Put(Item => week, Exp => 0, Aft => 2);
   New_Line;
end;

Rounding Floating-Point Numbers

declare
   a : float := 0.255;
begin
   Put("Unrounded: ");
   Put(Item => a, Exp => 0, Aft => 3);
   New_Line;
   Put("Rounded: ");
   Put(Item => a, Exp => 0, Aft => 2);
   New_Line;
end;

------

declare
   type vals is array(1..4) of float;
   a : vals := (3.3, 3.5, 3.7, -3.3);
begin
   for num in vals'range loop
      Put(Item => a(num), Exp => 0, Aft => 1);
      Put(Ada.Characters.Latin_1.HT);
      Put(Item => Float'Truncation(a(num)), Aft =>1, Exp => 0);
      Put(Ada.Characters.Latin_1.HT);
      Put(Item => Float'Floor(a(num)), Aft => 1,Exp => 0);
      Put(Ada.Characters.Latin_1.HT);
      Put(Item => Float'Ceiling(a(num)), Aft => 1,Exp => 0);
      New_Line;
   end loop;
end;
------------

Converting Between Binary and Decimal

-- Ada uses the notation Base#value# for a non-decimal value
-- Thus, a binary number is defined as 2#0011_0110#.
-- The underscores are optional, for readability only.

declare
   num : Integer := 2#0011_0110#;
begin
   Put("Decimal: ");
   Put(Item => num);
   New_Line;
   Put("Binary: ");
   Put(Item => num, Base => 2);
   New_Line;
end;

Operating on a Series of Integers

declare
   x : Integer := 5;
   y : Integer := 10;
begin
   for i in x..y loop
   -- i is set to every Integer from x to y, inclusive
      null;
   end loop;
end;

declare
   x : Integer := 5;
   y : Integer := 12;
   num : Integer := x;
begin
   loop
   -- operate on num
      num := num + 7; -- step size = 7
      exit when num > y;
   end loop;
end;

Put("Childhood is: ");
for num in 5..12 loop
   Put(Integer'Image(num));
end loop;
New_Line;
---------------

Working with Roman Numerals

---------------
-- No standard roman numeral package available
---------------

Generating Random Numbers

-- Generating random discrete values
declare
   type Rand_Range is range 25..75;
   package Rand_Int is new Ada.Numerics.Discrete_Random(Rand_Range);
   seed : Rand_Int.Generator;
   Num : Rand_Range;
begin
   Rand_Int.Reset(seed);
   Num := Rand_Int.Random(seed);
   Put_Line(Rand_Range'Image(Num));
end;
-- Generating a random 8 character password
declare
   subtype alphas is Character range 'A'..'z';
   package Rand_Alpha is new Ada.Numerics.Discrete_Random(alphas);
   seed : Rand_Alpha.Generator;
   Password : String(1..8);
begin
   Rand_Alpha.Reset(seed);
   for index in Password'Range loop
      Password(index) := Rand_Alpha.Random(seed);
   end loop;
   Put_Line("Random Password: " & Password);
end;

-- Generating Random Floating Point Numbers
declare
   seed : Ada.Numerics.Float_Random.Generator;
begin
   Ada.Numerics.Float_Random.Reset(seed);
   Put_Line("Random Float: " &
         Float'Image(Ada.Numerics.Float_Random.Random(seed)));
end;
--------

Generating Different Random Numbers

------------
-- Ada random number generators are required to yield a period of
-- at least (2^31)-2 or greater.
--------

Making Numbers Even More Random

------------
-- Ada does not provide a standard biased random number package
------------

Generating Biased Random Numbers

------------
-- Using the Cycle parameter of the Elementary Functions to define
-- a cycle of 0.0..359.99
declare
   use Ada.Numerics.Elementary_Functions;
   angle   : float := 45.0;
   degrees : constant float := 360.0;
   degreeSine : float;
begin
   DegreeSine := sin(X => angle, Cycle => degrees);
   Put_Line("Sine of " & float'Image(angle) &
            " degrees is " & float'Image(degreeSine));
end;

Doing Trigonometry in Degrees, not Radians

declare
   y: float;
   package Elm renames Ada.Numerics.Elementary_Functions;
begin
   y := Elm.Arccos(X => 0.7);
   Put_Line("arccos(0.7) = " & float'Image(y));
end;

Calculating More Trigonometric Functions

-- The Ada.Numerics.Elementary_Functions.Log function returns
-- a natural logarithm when no base is specified, and a log to
-- the specified base when a base is specified.
declare
   use Ada.Numerics.Elementary_Functions;
   answer : float := log(X => 10000.0, Base => 10.0);
begin
   Put_Line("Log10(10000) = " & Float'Image(answer));
end;

Taking Logarithms

-- Compute the multiplication of two given matrices.
declare
   type Data is array(Positive range <>,Positive range <>) of Integer;
   type Matrix(Rows : Positive; Cols : Positive) is record
      Mat : Data(1..Rows,1..Cols);
   end record;

   Matrix_Mismatch : exception;

   function Mat_Mult(Matrix1 : Matrix;
                     Matrix2 : Matrix) return Matrix is
      result : Matrix(Matrix1.Rows, Matrix2.Cols);
   begin
      if Matrix1.Rows /= Matrix2.Cols then
         raise Matrix_Mismatch;
      end if;
      for i in 1..Matrix1.Rows loop
         for j in 1..Matrix2.Cols loop
            for k in 1..Matrix1.Cols loop
               result.Mat(i,j) := result.Mat(i,j)+ (Matrix1.Mat(i,k) *
                         Matrix2.Mat(k,j));
            end loop;
         end loop;
      end loop;
      return result;
   end Mat_Mult;

   Mat1 : Matrix(Rows => 2,Cols => 3);
   Mat2 : Matrix(Rows => 3,Cols => 2);
   Mat3 : Matrix(Rows => 2,Cols => 2);
begin
   Mat1.Mat := ((3,2,3), (5,9,8));
   Mat2.Mat := ((4,7),(9,3),(8,1));
   Mat3 := Mat_Mult(Mat1, Mat2);
end;

Multiplying Matrices

declare
   package Cmplx_Flt is new
        Ada.Numerics.Generic_Complex_Types(float);
   use Cmplx_Flt;
   a : Cmplx_Flt.Complex := (3.0, 5.0);
   b : Cmplx_Flt.Complex := (2.0, -2.0);
   c : Cmplx_Flt.Complex;
begin
   c := a * b;
end;

Using Complex Numbers

-- Ada allows representation of any base from 2 through 16 on output
-- all Integers are stored internally as binary.
declare
   Num : Integer;
begin
   Put_Line("Gimme a number in decimal, octal, or hex:");
   Get(Num);
   Put_Line("Decimal value: " & Integer'Image(Num));
   Put("Octal Value: ");
   Put(Item => Num, Base => 8);
   New_Line;
   Put("Hexadecimal Value: ");
   Put(Item => Num, Base => 16);
   New_Line(2);
------
   Put_Line("Enter a file permission in octal: ");
   Get(Num);
   Put_Line("Decimal Value:" & Integer'Image(Num));
end;

Converting Between Octal and Hexadecimal

-- The Text Editing routines in Ada work for fixed decimal types
declare
   type Large_Type is delta 0.01 digits 10;
   package with_Commas is new
            Ada.Text_Io.Editing.Decimal_Output(Large_Type);
   use with_Commas;
   use Ada.Text_IO.Editing;

   Val : Large_Type := 12345678.90;
begin
   put(Val, To_Picture("ZZ_ZZZ_ZZ9.99"));
end;
----------------

Putting Commas in Numbers

-----------------
-- There are no standard Ada regular expression packages,
-- however, then GNAT compiler does provide some regular expression
-- packages as extensions.

end Pleac_Numbers;

Printing Correct Plurals

-----------------------------------------------------------------
------- Program Calculating Prime Factors
-----------------------------------------------------------------
-----with Ada.Text_Io; use Ada.Text_IO;

with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
with Ada.Command_Line; use Ada.Command_Line;

procedure Prime_Factors is
   type Found_List is array(Positive range <>) of Natural;
   type Factor_List (Max_Size : Positive) is record
      Factors : Found_List(1..Max_Size) := (Others => 0);
      Num_Found : Natural := 0;
   end record;

function getFactors(n : in Integer) return Factor_List is
   orig : Integer := n;
   new_n : Integer := n;
   Temp : Factor_List(Max_Size => n / 2);
   sqi  : Integer := 4;
   i    : Integer := 2;
begin
   while sqi <= new_n loop
     while (new_n mod i) = 0 loop
        new_n := new_n / i;
        if Temp.Factors(i) = 0 then
           Temp.Factors(i) := 1;
        else
           Temp.Factors(i) := Temp.Factors(i) + 1;
           Temp.Num_Found := Temp.Num_Found + 1;
        end if;
      end loop;
      sqi := (i + 1)**2;
      i := i + 1;
   end loop;
   if (new_n /= 1) and (new_n /= orig) then
      Temp.Factors(new_n) := 1;
      Temp.Num_Found := Temp.Num_Found + 1;
   end if;
   return Temp;
end getFactors;

procedure Display_Factors(Num : Integer; Item : in Factor_List) is
begin
   Put(Integer'Image(Num) & ": ");
   if Item.Num_Found = 0 then
      Put_Line("PRIME");
   else
      for index in Item.Factors'Range loop
         if Item.Factors(index) /= 0 then
            Put(Item => index, width => 1);
            if Item.Factors(index) > 1 then
               Put("^");
               Put(Item => Item.Factors(index), width => 1);
            end if;
            Ada.Text_Io.Put(" ");
         end if;
      end loop;
      New_Line;
   end if;
end Display_Factors;

begin
   if Argument_Count < 1 then
      Put_Line("Usage: " & Command_Name & " number...");
      return;
   end if;
   for arg in 1..Argument_Count loop
     Display_Factors(Positive'Value(Argument(arg)),
                     getFactors(Positive'Value(Argument(arg))));
   end loop;
end Prime_Factors;
------------------------------------------------------------------------------

Program: Calculating Prime Factors