Ada - Subprogram determining the biggest number - ada

The task is simple :
Create a subprogram of type function that receives exactly two parameters, both floats and returns the value of the number that is the greatest.
The execution should go as following:
Type in two floats: -13.12 2
-- User types in two numbers marked in bold
The greatest value was : 2.00
This is my code:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
procedure Test is
function Value(Float_1, Float_2 : in Float) return Float is
begin
if Float_1 > Float_2 then
return Float_1;
elsif Float_2 > Float_1 then
return Float_2;
end if;
end Value;
Float_1, Float_2 : Float;
begin
Put("Type in two numbers: ");
Get(Float_1);
Get(Float_2);
Put("The greatest value was: ");
if Float_1 > Float_2 then
Put(Float_1, Fore => 0, Aft => 2, Exp => 0);
elsif Float_2 > Float_1 then
Put(Float_2, Fore => 0, Aft => 2, Exp => 0);
end if;
end Test;
Although it works, I feel like I've overcomplicated it and haven't executed it well. For instance I haven't even used my subprogram Value at all in my main program, which I should do.
Any help is greatly appreciated!

Another approach uses a conditional expression:
function Max_Value (Float_1, Float_2 : in float) return float is
(if Float_1 > Float_2 then Float_1 else Float_2);
The conditional expression does the same thing as you were attempting while eliminating the need to return from the function in two different places.
Note that the logic simply returns Float_1 if it is greater than Float_2, otherwise it returns Float_2. Obviously, returning Float_2 when the two values are equal is a valid consequence of this logic.

Perhaps a better name for Value is Max_Value. The conditional within it is also not exhaustive. If the two numbers are equal, there is no return value. This can be corrected by using >= instead of >, at which point the only other option is that Float_2 is greater.
function Max_Value(Float_1, Float_2 : in Float) return Float is
begin
if Float_1 >= Float_2 then
return Float_1;
else
return Float_2;
end if;
end Max_Value;
Alternatively, as suggested by others, the attribute 'Max on Float can accomplish this much more concisely.
function Max_Value(Float_1, Float_2 : in Float) return Float is
begin
return Float'Max(Float_1, Float_2);
end Max_Value;
Or even more concisely:
function Max_Value(Float_1, Float_2 : in Float) return Float renames Float'Max;
Having the ability to pick the larger of two Floats using Max_Value there's now no need to have a conditional later on.
Put(Max_Value(Float_1, Float_2), Fore => 0, Aft => 2, Exp => 0);

As others have mentioned, Ada already provides this functionality. Thus, the most concise implementation would be
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
procedure Test is
function Max_Value (Left, Right : Float) return Float renames Float'Max;
begin
Put ("Type in two numbers: ");
Get (Float_1);
Get (Float_2);
Put ("The greatest value was: ");
Put (Max_Value (Float_1, Float_2));
end Test;
What you do here is declare a function Max_Value that renames the existing Float'Max function. Other answers have shown you how to implement the logic yourself.

Related

Why my loop invariant might not be preserved by any iteration?

I'm trying to write a code in Spark that computes the value of the polynomial using the Horner method. The variable Result is calculated by Horner, and the variable Z is calculated in the classical way. I've done a lot of different tests and my loop invariant is always true. However, I get the message:
loop invariant might not be preserved by an arbitrary iteration
Are there any cases where the loop invariant doesn't work or do you need to add some more conditions to the invariant?
Here's my main func which call my Horner function:
with Ada.Integer_Text_IO;
use Ada.Integer_Text_IO;
with Poly;
use Poly;
procedure Main is
X : Integer;
A : Vector (0 .. 2);
begin
X := 2;
A := (5, 10, 15);
Put(Horner(X, A));
end Main;
And Horner function:
package body Poly with SPARK_Mode is
function Horner (X : Integer; A : Vector)
return Integer
is
Result : Integer := 0;
Z : Integer := 0;
begin
for i in reverse A'Range loop
pragma Loop_Invariant (Z=Result*(X**(i+1)));
Result := Result*X + A(i);
Z := Z + A(i)*X**(i);
end loop;
pragma Assert (Result = Z);
return Result;
end Horner;
end Poly;
How is Vector defined? Is it something like
type Vector is array(Integer range <>) of Float;
In this case maybe the condition could fail if some indexes of A are negative. Also, does the invariant hold even if the first index of A is not zero? Maybe another case when the invariant fails is when A'Last = Integer'Last; in this case the i+1 would overflow.
Usually SPARK gives a reason, a counterexample, when it is not able to prove something. I would suggest you to check that, it can give you an idea of when the invariant fails. Keep in mind that the counterexamples are sometimes some very extreme case such as A'Last = Integer'Last. If this is the case you need to tell SPARK that A'Last = Integer'Last will never happen, maybe by defining a specific subtype for Vector index or by adding a contract to your function.

My code in Pascal does not want to work correctly. What is the problem in?

I am writing program: sum of real numbers using recursive function.
What is wrong with it? It shows me just last entered numebr.
type
Indexy = 1..100;
TPoleReal = array [Indexy] of Real;
var
j: word;
r, realRes: real;
tpr: TPoleReal;
function SoucetCisel(n: TPoleReal; j: word): real;
begin
if j>0 then begin
SoucetCisel:=SoucetCisel + n[j];
j:=j-1;
end
end;
begin i:=0; j:=0;
while not seekeof do begin
read(r); Inc(j);
tpr[j]:=r;
writeln(j, ' ', tpr[j]);
end;
realRes:= SoucetCisel(tpr, j);
writeln(realRes);
end.
For debugging purposes I suggest you simplify the main part of your code to
begin
i:=0;
j:=0;
tpr[j] := 1;
Inc(j);
tpr[2] := 2;
realRes:= SoucetCisel(tpr, j);
writeln(realRes);
end.
That should make it make it much easier to appreciate what the problem is.
The first problem with your SoucetCisel function is that it isn't actually recursive.
A recursive function is one which calls itself with altered arguments, as in the
archetypical Factorial function
function Factorial(N : Integer)
begin
if N = 1 then
Factorial := 1
else
Factorial := N * Factorial(N - 1);
end;
The recursive call in this is the line
Factorial := Factorial(N - 1);
Your SoucetCisel doesn't do that, it simply adds the initial value of the function result
to the value of n[j], so it is not recursive at all.
The other problem is that, as written, it has no defined return value. In all the
Pascal implementations I've come across, the return value is undefined on entry to the
function and stays undefined until some value is explicitly assigned to it. The
function result is usually some space on the stack which the compiler-generated
code of the function reserves but which initially (on entry to the function) holds some random value, resulting from previous usage of the stack.
So, what the result of your SoucetCisel function is evaluated from is effectively
SoucetCisel := ARandomNumber + n[j]
which of course is just another random number. Obviously, you fix this aspect
of your function by ensuring that an explicit assignment to the function result is made
immediately on entry to the function. As a general rule, all execution paths through a function should lead through a statement which explicitly assigns a
value to the function result.
Then, you need to rewrite the remainder of it so that it actually is recursive
in the way your task requires.
While you're doing those two things, I would suggest that you use a more
helpful parameter name than the anonymous 'n'. 'n' is usually used to refer to an uninteresting integer.
update I'm not sure from your comment whether it was supposed to be serious. In case it was, consider these two functions
function SumOfReals(Reals : TPoleReal; j : word): real;
var
i : Integer;
begin
SumOfReals := 0;
for i := 1 to j do
SumOfReals := SumOfReals + Reals[i];
end;
function SumOfRealsRecursive(Reals : TPoleReal; j : word): real;
var
i : Integer;
begin
SumOfRealsRecursive := Reals[j];
if j > 1 then
SumOfRealsRecursive := SumOfRealsRecursive + SumOfRealsRecursive(Reals, j -1);
end;
These functions both do the same thing, namely evaluate the sum of the contents
of the Reals array up to and including the index j. The first one does so iteratively,
simply traversing the Reals array, which the second does it recursively. However,
it should be obvious that the recursive version is absolutely pointless in this case because
the iterative version does the same thing but far more efficiently, because
it does not involve copying the entire Reals array for each recursive call, which the recursive version does.
As I told you in a comment before. Try this code for your pascal program:
type
Indexy = 1..100;
TPoleReal = array [Indexy] of Real;
var
j: word;
r, realRes: real;
tpr: TPoleReal;
function SoucetCisel(n: TPoleReal; j: word): real;
begin
if j>0 then begin
SoucetCisel:=SoucetCisel(n, j-1) + n[j];
end
end;
begin i:=0; j:=0;
while not seekeof do begin
read(r); Inc(j);
tpr[j]:=r;
writeln(j, ' ', tpr[j]);
end;
realRes:= SoucetCisel(tpr, j);
writeln(realRes);
end.

Cartesian Product of Lists Using Ada

I am currently working on programming this (https://rosettacode.org/wiki/Cartesian_product_of_two_or_more_lists) in Ada, I am trying to do a Cartesian product between different sets. I need help figuring it out, the main issue is how would I be able to declare empty Pairs and calculate that if it's empty, then the result should be empty. Thank you!
Numbers I am trying to use:
{1, 2} × {3, 4}
{3, 4} × {1, 2}
{1, 2} × {}
{} × {1, 2}
My code:
with Ada.Text_IO; use Ada.Text_IO; -- Basically importing the functions that will be used to print out the results.
procedure Hello is -- Procedure is where variables & functions are declared!
type T_Pair is array(1..2) of Integer; -- Declare a type of array that contains a set of 2 numbers (Used for final result!).
type T_Result is array(1..4) of T_Pair; -- Declare a type of array that contains a set of T_Pair(s), used to hold the result.
Demo1 : T_Result;
Demo1A : T_Pair := (1, 2);
Demo1B : T_Pair := (3, 4);
function Fun_CartProd(p1: T_Pair; p2: T_Pair) return T_Result is
results: T_Result;
i: integer := 1;
begin
for j in 1..2 loop
for h in 1..2 loop
results(i) := (p1(j), p2(h));
i := i + 1;
end loop;
end loop;
return results;
end Fun_CartProd;
begin -- This is where the statements go
Demo1 := Fun_CartProd(Demo1A, Demo1B);
for K in 1 .. Demo1'length loop
Put(" [");
for B in 1 .. Demo1(K)'length loop
Put(Integer'Image(Demo1(K)(B)));
if Demo1(K)'length /= B then
Put(",");
end if;
end loop;
Put("]");
if Demo1'length /= K then
Put(",");
end if;
end loop;
Put_Line(""); -- Create a new line.
end Hello;
Since each set of integers can be any length, including empty, I would start with a type that can handle all those situations:
type Integer_Set is array(Positive range <>) of Integer; -- Input type
type Integer_Tuple is array(Positive range <>_ of Integer; -- Output type
and you can represent the empty sets and tuples this way:
Empty_Set : constant Integer_Set(1..0) := (others => <>);
Empty_Tuple : constant Integer_Tuple(1..0) := (others => <>);
The other problem isn't just how many elements are in each set, but how many sets you will be finding the product of. For this I would recommend some kind of container. An array won't work here because each of the individual sets can have different sizes (including empty), but Ada has a variety of "indefinite" containers that can handle that. Here is an example using vectors:
package Set_Vectors is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive,
Element_Type => Integer_Set);
package Tuple_Vectors is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive,
Element_Type => Integer_Tuple);
and you can then represent an empty result as:
Empty_Tuple_Vector : constant Tuple_Vectors.Vector := Tupler_Vectors.Empty_Vector;
Now you can create a function that takes in a vector of sets and returns a Cartesian product which will also be a vector of sets:
function Cartesian_Product(Inputs : Set_Vectors.Vector) return Tuple_Vectors.Vector;
If one of the input sets is empty, you return an Empty_Tuple_Vector. You can check if one of the input sets are empty by checking their Length attribute result. It will be 0 if they are empty. Additionally if the input vector is completely empty, you can decide to either return Empty_Tuple_Vector or raise an exception. For example:
if Inputs'Length = 0 then
return Empty_Tuple_Vector; -- or raise an exception, etc.
end if;
for Set of Inputs loop
if Set'Length = 0 then
return Empty_Tuple_Vector;
end if;
-- Maybe do other stuff here if you need
end loop;
Note that the logic you presented assumes only pairs of inputs. I don't have enough experience to convert your logic to account for variable inputs, but perhaps someone can comment on that if you need it.
Also note as Flyx commented, this does not semantically check if a set is a set or not on the inputs (I.E. no duplicate values).

How to change the range of the range type?

Lets say I have
function x return boolean is
type range0 is range 1..1;
begin
canse x is
when 4=> range0:=firstArray'range;
when 5=> range0:=secondArray'range;
when 6=> range0:=1..100;
end case;
end x;
Basically I would like to change the range of range0 on the go? How may I accomplish this without using the declare block?
Basically I would like to change the range of range0 on the go? How may I accomplish this without using the declare block?
Hm...
In Ada 2012 you can use if- and case-expressions, so you could have something like this:
Type Array_Type is Array(Positive Range <>) of Integer;
Array_1 : Array_Type(1..128);
Array_2 : Array_Type(33..63);
-- your variant-selector
Use_1 : constant Boolean:= True;
-- Your variant-range here:
Subtype Variant_Range is Positive Range
(if Use_1 then Array_1'First else Array_2'First)
..(if Use_1 then Array_1'Last else Array_2'Last);
Array_3 : Array_Type( Variant_Range );
All that said, this probably isn't the best way to go about it and using a declare-block is very likely going to be more easily maintained.
You could technically satisfy the stated requirements by converting the obvious way (declare block) into a local procedure :
function x return boolean is
procedure use_dynamic_range(first,last : in integer) is
type range0 is new integer range first .. last;
begin
null;
end use_dynamic_range;
begin
case z is
when 4=> use_dynamic_range(firstArray'first, firstArray'last);
when 5=> use_dynamic_range(secondArray'first, secondArray'last);
when 6=> use_dynamic_range(1,100);
end case;
end x;
Because it's a local procedure it executes in the same scope as the equivalent declare block, therefore it can access everything visible within X, so you don't need to pass it a huge parameter list.
What about something like :
function x return Boolean is
type Range_Info_Type is
record
First : Integer;
Last : Integer;
end record;
function Get_Range_Info_Type return Range_Info_Type is
begin
case z is
when 4=> return Range_Info_Type'(First => firstArray'First,
Last => FirstArray'Last);
when 5=> return Range_Info_Type'(First => secondArray'First,
Last => secondArray'Last);
when 6=> return Range_Info_Type'(First => 1,
Last => 100);
when others => return Range_Info_Type'(First => 1,
Last => 1);
end case;
end;
MyTypeInfo : constant Range_Info_Type := Get_Range_Info_Type;
-- Now declare the actual type I want to use.
type range0 is new Integer range MyTypeInfo.First .. MyTypeInfo.Last;
begin
return true;
end x;
A declare block might be easier to understand by this should do the trick.
Note that you cannot write type range0 is range <expr>..<expr> in your case since expr should be a static expression (see RM 3.5.4)
Another non declare-block answer from Ada 2012:
Minimum : Integer := Integer'First; --' SO highlight correction
Maximum : Integer := Integer'Last; --' *same*
Function In_Range(X : Integer) return Boolean is
( X in range Minimum..Maximum );
Subtype Variant_Range is Integer Range Integer
with Dynamic_Predicate => In_Range(Variant_Range);
WARNING: Though this should work, I have not tested it.

Ada sin(x) Computing with Taylor-series

I'm an absolute beginner in Ada and I'm trying to calculate sin(x) [sin(3) now] by using Taylor-series, but I just can't get it to work.
So here is my procedure:
with Ada.Float_Text_IO;
with Mat;
procedure SinKoz is
X:Float:=3.0;
Szamlalo:Float:=0.0;
begin
for I in 1..100 loop
Szamlalo := Szamlalo + ((-1.0)**I)*(X**(2.0*I+1.0))/Mat.Faktorialis(2*I+1);
end loop;
Ada.Float_Text_IO.Put( Szamlalo );
end SinKoz;
And inside Mat, here is my Faktorialis, which calculates the factorial of 2*I+1:
function Faktorialis( N: Float ) return Float is
Fakt : Float := 1.0;
begin
for I in 1..N loop
Fakt := Fakt * I;
end loop;
return Fakt;
end Faktorialis;
When i'm trying to compile my code, this error comes up:
exponent must be of type Natural, found type "Standard.Float"
I hope you can help me trying to figure out what went wrong with my types!
The first question is : do you need to raise X to a non-integer power?
It looks to me as if you don't : in which case replace X**(2.0*I+1.0) with X**(2*I+1) and all will be well.
But if you really do (perhaps not here, but in another application) you just need to make such an operator visible : there's one for Float in the package Ada.Numerics.Elementary_Functions so precede your function with
with Ada.Numerics.Elementary_Functions;
use Ada.Numerics.Elementary_Functions;
and it should work as written.
Finally, if you have created your own float type, you can instantiate the generic package Ada.Numerics.Generic_Elementary_Functions with your type as its parameter, to create a set of these functions specifically for your type.
Gotta love Ada's strong typing.
Off the top of my head, I suspect your problem may be this line:
Szamlalo := Szamlalo + ((-1.0)**I)*(X**(2.0*I+1.0))/Mat.Faktorialis(2*I+1);
2.0*I+1.0 is going to return a Float. Not a Natural. You could try wrapping that in Integer() or Natural() (Natural is a subtype of Integer) and see if that helps.

Resources