How do you get the square root in Ada? - ada

So I have been given an assignment to read in a file put the numbers into two matrices, multiply the matrices, and finally put the output into a .txt file.
I have never used Ada before and I figured it would be a good challenge. I am stuck in trying to determine the bounds for the two separate arrays.
This is what I currently have:
currentSpread := I;
g := Ada.Numerics.Generic_Complex_Elementary_Functions.Sqrt(I);
while J < g loop
if(I mod J = 0) THEN
if(currentSpread > ((I/J - J)/2)) THEN
currentSpread := ((I/J - J)/2);
arrayBounds := J;
end if;
end if;
J := J + 1;
end loop;
The problem I am having is with the sqrt function. I want to find the factors for the best bounds of the matrix multiplication and this was the only way that I thought to implement it.
The error I am getting is:
invalid prefix in selected component "Ada.Numerics.Generic_Complex_Elementary_Functions"
Thanks a lot for any help.
--Update
Full Code as requested:
with Ada.Text_IO;use Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Numerics.Generic_Complex_Elementary_Functions;
with Ada.Numerics.Generic_Elementary_Functions;
with Ada.Numerics.Complex_Elementary_Functions;
with Ada.Numerics.Generic_Complex_Types;
procedure Main is
dataFile : File_Type;
resultFile : File_Type;
value : Integer;
I : Integer := 0;
J : Integer;
currentSpread : Integer;
arrayBounds : Integer;
g : Integer;
begin
Ada.Text_IO.Open(File => dataFile, Mode => Ada.Text_IO.In_File, Name =>"C:\Users\Jeffrey\Desktop\data.txt");
while not End_Of_File(dataFile) loop
Ada.Integer_Text_IO.Get(File => dataFile, Item => value);
Ada.Integer_Text_IO.Put(Item => value);
Ada.Text_IO.New_Line;
I := I + 1;
end loop;
Ada.Integer_Text_IO.Put(I);
I := I/2;
J := 1;
currentSpread := I;
g := Ada.Numerics.Generic_Complex_Elementary_Functions.Sqrt(I);
while J < g loop
if(I mod J = 0) THEN
if(currentSpread > ((I/J - J)/2)) THEN
currentSpread := ((I/J - J)/2);
arrayBounds := J;
end if;
end if;
J := J + 1;
end loop;
declare
type newArray is array(Integer range <>, Integer range<>) of Integer;
X : Integer := J;
Y : Integer := I/J;
Arr1 : newArray(1..Y, 1..X);
Arr2 : newArray(1..X, 1..Y);
finAnswer : newArray(1..X, 1..X);
begin
for z in 1 .. X loop
for k in 1 .. Y loop
Ada.Integer_Text_IO.Get(File => dataFile, Item => value);
Arr1(z, k) := value;
end loop;
end loop;
for z in 1 .. Y loop
for k in 1 .. X loop
Ada.Integer_Text_IO.Get(File => dataFile, Item => value);
Arr2(z, k) := value;
end loop;
end loop;
for l in 1 .. X loop
for m in 1 .. Y loop
for n in 1 .. X loop
finAnswer(l, n) := finAnswer(l, n) + Arr1(l, n)* Arr2(n, m);
end loop;
end loop;
end loop;
end;
Ada.Text_IO.Close(File => dataFile);
end Main;
I am using the square root exclusively to figure out the factors of a number nothing else. How I have it set up now is it will go up to the square root and then it will take the smallest spread of the factors. I do not care about rounding errors or anything else if it isn't a perfect square it can round either way.
Thanks.

Generic_Complex_Elementary_Functions is a generic package. It cannot be used directly. That is why the compiler gives you an error on this line:
Ada.Numerics.Generic_Complex_Elementary_Functions.Sqrt(I);
To use it, you have to instantiate the generic Generic_Complex_Types with the floating-point type you want to use, and then instantiate Generic_Complex_Elementary_Functions with an instance of Generic_Complex_Types. Fortunately, you don't have to go through all that if you're willing to use the built-in type Float; the language provides Ada.Numerics.Complex_Elementary_Functions for you, that uses Float as the floating-point type, or Ada.Numerics.Long_Complex_Elementary_Functions that uses Long_Float if your compiler vendors support it.
However, I don't think you want to use Complex anything. That deals with complex numbers, and I doubt that you want to use those. Use Ada.Numerics.Elementary_Functions (or Long_Elementary_Functions), which deal with real numbers.
Finally, even this isn't going to work:
Ada.Numerics.Elementary_Functions.Sqrt(I)
if I is an integer, because the argument type needs to be a Float. You'll have to use a type conversion.
Ada.Numerics.Elementary_Functions.Sqrt(Float(I))

Related

Constraint Error running Heapify SiftDown

I am writing this code in Ada for a class where we have to teach ourselves the code. I understand heap sort, but the Ada syntax is really confusing me. I don't understand why I am getting a constraint error in this sort function.
Essentially we have to pass array "A" into this procedure, and it should organize it. I get the constraint error at siftDown(A(Start...A'Last));
Thank you in advance
Procedure sort_3(A : in out array_type) is
procedure swap(Left : in out Integer; Right : in out Integer) is
temp : Integer;
begin
temp := Left;
Left := Right;
Right := Temp;
end swap;
procedure siftDown(A : in out array_type) is
Count : Integer := 1;
root : Integer := Integer'Pos(A'First);
child : Integer := Integer'Pos(A'Last);
last : Integer := Integer'Pos(A'Last);
begin
while root * 2 + 1 <= last loop
child := root * 2 + 1;
if child + 1 <= last and then A(Integer'Val(child)) < A(Integer'Val(child + 1)) then
child := child + 1;
end if;
if A(Integer'Val(root)) < A(Integer'Val(child)) then
swap(A(Integer'Val(root)), A(Integer'Val(child)));
root := child;
else
exit;
end if;
end loop;
end siftDown;
procedure heapify(A : in out array_type) is
Count : Integer := 0;
First_Pos : Integer;
Last_Pos : Integer;
Start : Integer;
begin
First_Pos := A'First;
Last_Pos := A'Last;
Start := Integer'Val((Last_Pos - First_Pos + 1) / 2);
loop
siftDown(A(Start...A'Last));
if Start > Integer'First then
Start := Integer'Pred(Start);
else
exit;
end if;
end loop;
end heapify;
Last_Index : Integer := Integer'Last;
begin
heapify(A);
while Last_Index > Integer'First loop
swap(A(Last_Index), A(A'First));
Last_Index := Integer'Pred(Last_Index);
siftDown(A(A'First..Last_Index));
end loop;
end sort_3;
You have a syntax error in the code - an extra dot in A(Start...A'Last).
The syntax A(Start..A'Last) means a slice, part of array from Start to the last element. The Constraint_Error means that Start not in array bounds. Try to add
Ada.Text_IO.Put_Line (Start'Image);
before that line and you will see Start values and when it became out of the A'Range.
Your code has some references to Integer'First and Integer'Last, which are huge values that have nothing to do with the array A and its values. I'm pretty sure you should use A'First and A'Last instead.
Also a note on style: Using the same identifier, "A", for the parameter of the local (inner, nested) procedures as for the parameter "A" of the containing (outer) procedure, when these arrays can be different, invites confusion and errors. Better to use different identifiers.

How to use Assert and loop_invariants

Specification:
package PolyPack with SPARK_Mode is
type Vector is array (Natural range <>) of Integer;
function RuleHorner (X: Integer; A : Vector) return Integer
with
Pre => A'Length > 0 and A'Last < Integer'Last;
end PolyPack ;
I want to write body of PolyPack package with Assert and loop_invariants that the gnatprove program can prove my function RuleHorner correctness.
I write my function Horner but I don;t know how put assertions and loop_invariants in this program to prove its corectness :
with Ada.Integer_Text_IO;
package body PolyPack with SPARK_Mode is
function RuleHorner (X: Integer; A : Vector) return Integer is
Y : Integer := 0;
begin
for I in 0 .. A'Length - 1 loop
Y := (Y*X) + A(A'Last - I);
end loop;
return Y;
end RuleHorner ;
end PolyPack ;
gnatprove :
overflow check might fail (e.g. when X = 2 and Y = -2)
overflow check might fail
overflow check are for line Y := (Y*X) + A(A'Last - I);
Can someone help me how remove overflow check with loop_invariants
The analysis is correct. The element type for type Vector is Integer. When X = 2, Y = -2, and A(A'Last - I) is less than Integer'First + 4 an underflow will occur. How do you think this should be handled in your program? Loop invariants will not work here because you cannot prove that an overflow or underflow cannot occur.
Is there a way you can design your types and/or subtypes used within Vector and for variables X and Y to prevent Y from overflowing or underflowing?
I am also curious why you want to ignore the last value in your Vector. Are you trying to walk through the array in reverse? If so simply use the following for loop syntax:
for I in reverse A'Range loop

Is it necessary to wrap shared array data in a protected type?

I am aware that it is generally bad practice (and the ARM probably says that this is undefined behavior), but I am attempting to write a fast text parser containing many floating point numbers and it would be very expensive to wrap the loaded text into a protected type given that the data is examined character by character and may have up to a million floats or pass a slice on the stack.
Is it possible in Ada (GNAT) to "safely" divide up an unprotected array for consumption with multiple tasks given that the array is never written and only read?
As in:
Text : array (1..1_000_000) of Character := ...
begin
Task_1.Initialize (Start_Index => 1, End_Index => 10_000);
Task_2.Initialize (Start_Index => 10_001, End_Index => 20_000);
...
Yes. That is safe because there is no race condition associated with reading the data and there is no temporally overlapping write operation.
For example, the following code uses such a technique to perform parallel addition on an array of integers.
package Parallel_Addition is
type Data_Array is array(Integer range <>) of Integer;
type Data_Access is access all Data_Array;
function Sum(Item : in not null Data_Access) return Integer;
end Parallel_Addition;
package body Parallel_Addition is
---------
-- Sum --
---------
function Sum (Item : in not null Data_Access) return Integer is
task type Adder is
entry Set (Min : Integer; Max : Integer);
entry Report (Value : out Integer);
end Adder;
task body Adder is
Total : Integer := 0;
First : Integer;
Last : Integer;
begin
accept Set (Min : Integer; Max : Integer) do
First := Min;
Last := Max;
end Set;
for I in First .. Last loop
Total := Total + Item (I);
end loop;
accept Report (Value : out Integer) do
Value := Total;
end Report;
end Adder;
A1 : Adder;
A2 : Adder;
R1 : Integer;
R2 : Integer;
Mid : constant Integer := (Item'Length / 2) + Item'First;
begin
A1.Set (Min => Item'First, Max => Mid);
A2.Set (Min => Mid + 1, Max => Item'Last);
A1.Report (R1);
A2.Report (R2);
return R1 + R2;
end Sum;
end Parallel_Addition;
with Parallel_Addition; use Parallel_Addition;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
procedure Parallel_Addition_Test is
The_Data : Data_Access := new Data_Array (1 .. Integer'Last / 5);
Start : Time;
Stop : Time;
The_Sum : Integer;
begin
The_Data.all := (others => 1);
Start := Clock;
The_Sum := Sum (The_Data);
Stop := Clock;
Put_Line ("The sum is: " & Integer'Image (The_Sum));
Put_Line
("Addition elapsed time is " &
Duration'Image (Stop - Start) &
" seconds.");
Put_Line
("Time per addition operation is " &
Float'Image(Float(Stop - Start) / Float(The_Data'Length)) &
" seconds.");
end Parallel_Addition_Test;

expected type "..." defined at ....... error in Ada

I have such a Karatsuba algorithm implementation I have written in ADA.
procedure Karatsuba (Factor_1, Factor_2 : in Number; Product : out Number) is
m : Integer;
m2 : Integer;
low1 : Number := (0,1);
high1 : Number := (0,1);
low2 : Number := (0,1);
high2 : Number := (0,1);
z0 : Index;
z1 : Index;
z2 : Index;
x : Integer;
y : Integer;
hc1 : Index;
hc2 : Index;
begin
low1 := (others => 0);
high1 := (others => 0);
low2 := (others => 0);
high2 := (others => 0);
if Factor_1'Length = 1 or Factor_2'Length = 1 then
Standard(Factor_1, Factor_2,Product);
end if;
-- calculates the size of the numbers
m := Integer'Max(Factor_1'Length, Factor_2'Length);
m2 := m / 2;
-- split the digit sequences about the middle
for Factor_1_Index in Factor_1'Range loop
x := x + 1;
if x <= m2 then
low1(Factor_1_Index) := Factor_1(Factor_1_Index);
else
high1(hc1) := Factor_1(Factor_1_Index);
hc1 := hc1 + 1;
end if;
end loop;
for Factor_2_Index in Factor_2'Range loop
y := y + 1;
if y <= m2 then
low2(Factor_2_Index) := Factor_2(Factor_2_Index);
else
high2(hc2) := Factor_2(Factor_2_Index);
hc2 := hc2 + 1;
end if;
end loop;
-- 3 calls made to numbers approximately half the size
z0 := Karatsuba(low1, low2, Product);
z1 := Karatsuba((low1 + high1), (low2 + high2), Product);
z2 := Karatsuba(high1, high2, Product);
Product := (z2*10**(2*m2))+((z1-z2-z0)*10**(m2))+(z0);
end Karatsuba;
On the last 4 lines before "end Karatsuba" line, I get the error "expected type 'Index' defined at ...". The errors I'm receiving are, respectively,
expected type "Index" defined at ....
found package or procedure name
there is no applicable operator "+" for type "Number" defined at ......
This is another class that I have assigned some variables:
package ITI8590.Natural_Number_Multiplication is
type Digit is range 0 .. 1;
type Index is new Positive;
type Number is array (Index range <>) of Digit;
for Digit'Size use 1;
procedure Standard(Factor_1, Factor_2 : in Number; Product : out Number);
procedure Karatsuba(Factor_1, Factor_2 : in Number; Product : out Number);
end ITI8590.Natural_Number_Multiplication;
Now why I get this error? I couldn't solve it, and I'm stuck in it. Could you help me?
Thanks,
Karatsuba is a procedure, so at the end instead of
z0 := Karatsuba(low1, low2, Product);
z1 := Karatsuba((low1 + high1), (low2 + high2), Product);
z2 := Karatsuba(high1, high2, Product);
it should probably read
Karatsuba(low1, low2, z0);
Karatsuba((low1 + high1), (low2 + high2), z1);
Karatsuba(high1, high2, z2);
which requires you to declare z0, z1, z2 as Number rather than Index. Note, Product is an out parameter to the procedure, so all your code achieved was to overwrite it twice with intermediate results (3 times, counting the call to Standard above).
But then you have a problem: the compiler says
yusuf.ada:25:12: unconstrained subtype not allowed (need initialization)
yusuf.ada:25:12: provide initial value or explicit array bounds
which is calling for something related to the way you have declared low1 etc:
low1 : Number := (0,1);
high1 : Number := (0,1);
low2 : Number := (0,1);
high2 : Number := (0,1);
The trouble with this approach is that you’ve now constrained the bounds of the variables: low1 is fixed to have 2 elements (set to values that you then overwrite), and can’t be expanded. I don’t know how the algorithm is supposed to work, but this seems unlikely to be right; for a start, what happens if the inputs have more than 2 digits?
One approach that might work is to use the number of digits in the input parameters:
Max_Digits : constant Positive := Factor_1’Length + Factor_2’length;
pragma Assert (Product’Length >= Max_Digits, “possible overflow”);
low1 : Number (1 .. Max_Digits) := (others => 0);
etc.
And, as ajb has commented, you’ll need to define operators +, -, *, ** between Numbers and Integers as needed, particularly in the expression (z2*10**(2*m2))+((z1-z2-z0)*10**(m2))+(z0) in the last line of the procedure.

Pascal. Recursive function to count amount of odd numbers in the sequence

I need to write recursive function to count amount of odd numbers in the sequence
Here my initial code:
program OddNumbers;
{$APPTYPE CONSOLE}
uses
SysUtils;
function GetOddNumbersAmount(const x: array of integer; count,i:integer):integer;
begin
if((x[i] <> 0) and (x[i] mod 2=0)) then
begin
count:= count + 1;
GetOddNumbersAmount:=count;
end;
i:=i+1;
GetOddNumbersAmount:=GetOddNumbersAmount(x, count, i);
end;
var X: array[1..10] of integer;
i,amount: integer;
begin
writeln('Enter your sequence:');
for i:=1 to 10 do
read(X[i]);
amount:= GetOddNumbersAmount(X, 0, 1);
writeln('Amount of odd numbers: ', amount);
readln;
readln;
end.
When i type the sequence and press "enter", program closed without any errors and i can't see the result.
Also, i think my function isn't correct.
Can someone help with that code?
UPD:
function GetOddNumbersAmount(const x: array of integer; count,i:integer):integer;
begin
if((x[i] <> 0) and (x[i] mod 2<>0)) then
count:= count + 1;
if(i = 10) then
GetOddNumbersAmount:=count
else
GetOddNumbersAmount:=GetOddNumbersAmount(x, count, i+1);
end;
You don't provide an end of recursion, i.e., you always call your function GetOddNumbersAmount again, and your program never terminates. Thus, you get an array index error (or a stack overflow) and your program crashes.
Please note, that every recursion need a case where it terminates, i.e. does not call itself. In your case, it should return if there are no elements in the array left.
In addition, you are counting the even numbers, not the odd ones.
You passed a static array to a dynamic so the index get confused:
Allocat the array with
SetLength(X,10)
allocates an array of 10 integers, indexed 0 to 9.
Dynamic arrays are always integer-indexed, always starting from 0!
SetLength(X,10)
for it:=0 to 9 do begin
X[it]:= random(100);
And second if you know the length a loop has more advantages:
function GetEvenNumbersAmount(const x: array of integer; count,i:integer):integer;
begin
for i:= 0 to length(X)-1 do
if((x[i] <> 0) and (x[i] mod 2=0)) then begin
inc(count);
//write(inttostr(X[i-1])+ ' ') :debug
end;
result:=count;
end;

Resources