I have a pretty simple Ada project on my hands. The task is to take a collection of a "voter's" votes and compare it to each "candidate's" score and determine which candidate best matches the voter.
The input looks like this, followed by the output that should be put out:
Input:
0 0 0 1 1 1 -1 -1 -1 1
7
A
1 1 1 1 1 1 1 1 1 1
B
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
C
1 -1 1 -1 1 -1 1 -1 1 -1
D
1 0 1 0 1 0 1 0 1 0
E
0 -1 0 -1 0 -1 0 -1 0 -1
F
1 1 1 1 0 0 0 0 0 0
G
0 0 0 1 -1 0 0 -1 1 1
Output:
A
F
G
So far, I have a procedure that will take the votes of each candidate and compare them to the votes of the voter. I know what I need to do as I have done it before in Java, but I am not sure how I should take the input in Ada. Here is what I have so far.
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;
procedure Candidates is
-- take an array of candidates and determine which candidate best matches
-- the user's votes, then return those candidates
Number_Of_Candidates: Integer;
subtype VoterArray_Index is Integer range 1..10;
subtype CandidatesArray_Index is Integer range 1..Number_Of_Candidates;
type VoterArray is array(VoterArray_Index) of Integer;
type CandidatesArray is array(Character range 'A' .. 'Z') of array;
type Best_CandidatesArray is array(CandidatesArray_Index) of array;
Voter: VoterArray;
Candidates: CandidatesArray;
Best_Candidates: Best_CandidatesArray;
function Get_Input() is
-- get the input and put it into the correct arrays
Current_Line : string;
begin
Get(Current_Line);
function Get_Best_Score(CandidatesArray: in out CandidatesArray) is
-- go through the arrays and find the best score
SameAnswers: Integer;
DifferentAnswers: Integer;
BestScore: Integer;
subtype CandidateArray is array(VoterArray_Index) of Integer;
Candidate: CandidateArray;
begin
for I in CandidatesArray_Index loop
Candidate := Candidates(I);
for J in VoterArray_Index loop
if Candidate(J) /= 0 and Voter(J) /= 0 then
if Candidate(J) /= Voter(J) then
DifferentAnswers := DifferentAnswers + 1
else
SameAnswers := SameAnswers + 1
end if;
end if;
end loop;
if SameAnswers - DifferentAnswers >= BestScore then
Best_Candidates(I) := Candidate;
end if;
SameAnswers := 0;
DifferentAnswers := 0;
end loop;
end Get_Best_Score;
As you can see, I'm not sure how to take the numbers and put them into an array. If you have any suggestions or a different way I should go about things, I'm all ears.
Thanks in advance.
You could use streams in order to read the data in:
Integer'Read( STREAM_HANDLE, VARIABLE )
Another option is reading the values via Get for each element of your array, I'd recommend a helper-function in case you need to tweak the procedure for handling format changes:
Function Get_Vote ( File : File_Type ) Return Integer is
begin
Return Result : Integer do
Integer_IO.Get(
File => File,
Item => Result
);
End return;
end Read_Votes;
and
For Index in VOTE_ARRAY'range loop
VOTE_ARRAY( Index ) := Get_Vote( INPUT_FILE );
End loop;
Because the number of rows is given in the file, a constrained array has to be large enough to hold all possible elements. Instead, you can declare an unconstrained array:
subtype Voter_Index is Positive range 1 .. 10;
type Voter_Array is array(Voter_Index) of Integer;
type Candidate_Array is array(Character range <>) of Voter_Array;
Later, when you know the actual count, you can allocate only the space actually required for the array. This declaration puts Candidates on the stack in a nested scope:
Number_Of_Candidates := ...;
declare
Candidates : Candidate_Array(
'A' .. Character'Val(Character'Pos('A') + Number_Of_Candidates));
begin
...
end;
Alternatively, you can allocate space on the heap:
type Candidate_Array_Ptr is access Candidate_Array;
Candidates: Candidate_Array_Ptr;
begin
Number_Of_Candidates := ...;
Candidates := new Candidate_Array(
'A' .. Character'Val(Character'Pos('A') + Number_Of_Candidates));
end;
In either case, you can access the array elements as required:
for i in Candidates'Range loop
for j in Voter_Array'Range loop
Ada.Integer_Text_IO.put(Candidates(i)(j), 5);
end loop;
Ada.Text_IO.New_Line;
end loop;
Addendum: This approach assumes that candidate names are consecutive Characters. As an alternative, consider an array of Candidate_Record, where each Name is read from the file:
type Candidate_Record is
record
Name : Character;
Votes : Voter_Array;
end record;
type Candidate_Array is array(Positive range <>) of Candidate_Record;
Candidates : Candidate_Array(1 .. Number_Of_Candidates);
for i in Candidates'Range loop
Ada.Text_IO.Put(Candidates(i).Name & ':');
for j in Voter_Array'Range loop
Ada.Integer_Text_IO.Put(Candidates(i).Votes(j), 5);
end loop;
Ada.Text_IO.New_Line;
end loop;
Related
I have made a program for obtaining a list of prime numbers in ADA and using the following online compiler:
https://rextester.com/l/ada_online_compiler
My code is the following:
--GNAT 8.3.0
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO;
procedure prime is
function isPrime(n:in Integer) return Boolean is
begin
for i in 2..n loop
if n mod i=0 then
return False;
end if;
end loop;
return True;
end isPrime;
begin
for i in 1..100 loop
if isPrime(i)=True then
Ada.Text_IO.Put_Line(Integer'Image(i));
end if;
Ada.Text_IO.Put_Line(Integer'Image(i));
end loop;
end prime;
And instead of printing a list of primes it only print 1. I have program the same code in C and no problem at all.
Your for loop in isPrime() checks every value higher than one as "n mod n = 0" which will cause you to return false for every value higher than 1. Change the for loop condition to
for i in 2..(n-1) loop
and work from there
Expanding on Jere's approach, several simple primality tests will simplify the divisibility test in the isPrime loop:
The only even prime, 2, can be handled immediately:
if N = 2 then
return True;
end if;
All remaining even numbers can be eliminated:
if N mod 2 = 0 then
return False;
end if;
This leaves odd numbers in the range 3 .. √N to check:
for i in 3 .. Positive (Sqrt (Float (N))) loop
if N mod i = 0 then
…
end if;
end loop;
It is even better by defining a Prime_Number type containing prime numbers.
subtype Prime_Number is Positive range 2 .. Positive'Last with
Dynamic_Predicate => (for all I in 2 .. (Prime_Number / 2)
=> (Prime_Number mod I) /= 0);
Then, use the code segment below to print out all prime numbers between 2 .. 100 range.
for Index in Positive range 2 .. 100 loop
if Index in Prime_Number then
Put_Line ("Prime number: " & Index'Image);
end if;
end loop;
declare
K number;
Lnumber;
f number;
function prime(n in number, I in number) return is flag
begin
i:=2;
flag:=1;
n:=&n;
for i in 2..n/2
loop
if mod(n,i)=0
then
flag:=0;
exit;
end if;
end loop;
if flag=1
then
dbms_output.put_line('prime');
else
dbms_output.put_line('not prime');
end if;
return flag;
end;
begin
k:=4;
L:=1;
f:= prime(n,i);
dbms_output.put_line(given number is ||flag);
end;
/
I am getting output as this I wonder what is wrong with my code:
Enter value for n: 4
old 9: n:=&n;
new 9: n:=4;
declare
*
ERROR at line 1:
ORA-06540: PL/SQL: compilation error
ORA-06553: PLS-906: Compilation is not possible
q2
SQL> DECLARE
num NUMBER;
3 c NUMBER;
4
5 PROCEDURE fact (x IN NUMBER, f OUT NUMBER)
6 IS
7 l_var NUMBER := 1;
8 BEGIN
9 FOR i IN 1 .. x
10 LOOP
11 l_var := l_var * i;
12 END LOOP;
13
14 f := l_var;
15 END;
16 BEGIN
17 num := 6;
18 fact (num, c);
19 DBMS_OUTPUT.put_line (' Factorial of ' || num || ' is ' || c);
20 END;
.
in this 2nd code the result is not getting displayed , not only for this even for other codes it is showing the line PL/SQL procedure successfully completed. but the results are not displaying what is wrong with it
A fixed version of q1 might be something like this (comments inline):
declare
-- k number; -- not used
-- l number; -- previously "lnumber;" not used anyway
f number;
function prime
( n in number ) -- "i" parameter never used
return number -- added return type
is
flag number := 1; -- added datatype, initial value and semicolon
begin
-- i := 2; -- Can't modify an IN parameter
-- flag := 1; -- not needed, can assign a value when declaring
-- n := &n; -- Can't modify an IN parameter
for i in 2 .. n / 2 loop
if mod(n, i) = 0 then
flag := 0;
exit;
end if;
end loop;
if flag = 1 then
dbms_output.put_line('prime');
else
dbms_output.put_line('not prime');
end if;
return flag;
end prime; -- added closing tag for clarity
begin
-- k := 4; -- not used
-- l := 1; -- not used
-- f := prime(n, i); -- n and i are not declared
f := prime(123);
dbms_output.put_line('prime check returns '|| f); -- added quotes, changed "flag" to "f"
end;
Also I formatted the code to make it more readable. This also helps when writing code, as it keeps the structure clearly visible and makes some errors more obvious.
q2 works for me, so you probably just need to check how whatever tool you are using displays dbms_output. In some tools there is a checkbox, others require a set server output on command.
You can also provide a function implementation of your factorial procedure:
declare
num number;
c number;
procedure fact
( num in number
, f out number )
is
begin
f := 1;
for i in 2 .. num loop
f := f * i;
end loop;
end fact;
function fact
( num number )
return number
is
f number;
begin
fact(num, f);
return f;
end fact;
begin
num := 6;
fact(num, c);
dbms_output.put_line('Factorial of ' || num || ' is ' || c);
dbms_output.put_line('Factorial of ' || num || ' is ' || fact(num));
end;
I've to create a function which print the Fibonacci series as its result. I've used a varray in the program below but it is giving me an error saying "PLS-00201: identifier 'ARRAY' must be declared" on line no. 2.
create function fibonacci7(x int)
return VARRAY
is
type fib IS VARRAY(25) OF VARCHAR(10);
a number(3):=1;
b number(3):=1;
c number(3);
i number(3):=1;
begin
while a<=n
loop
fib(i) := a;
c:=a+b;
a:=b;
b:=c;
i:=i+1;
end loop;
return codes_;
end ;
/
select fibonacci7(5) from dual;
I think this will do what you want. VARRAY's have a little different syntax than what you were using.
set serveroutput on size 1000000
create or replace type fibtype AS VARRAY(25) OF NUMBER;
/
create or replace function fibonacci7(n number)
return fibtype
is
fib fibtype := fibtype();
a number:=1;
b number:=1;
c number;
i number:=1;
begin
fib.extend(n);
while i<=n
loop
fib(i) := a;
c:=a+b;
a:=b;
b:=c;
i:=i+1;
end loop;
return fib;
end ;
/
declare
i number;
fib fibtype := fibtype();
begin
fib := fibonacci7(6);
for i in 1..fib.count loop
dbms_output.put_line(to_char(fib(i)));
end loop;
end;
/
Here is the output.
1
1
2
3
5
8
Bobby
p.s. Fixed to work with fib(6) and made array numbers
In this code, I am asking the user to input two integers (Index, Mindex) and then I display all the integers between 1..Index and 1..Mindex. What my problem is here that I do not know how to multiply the values of Integers in Index and Integers in `Mindex and then add up the product of these two together
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Add is
Index, Mindex : Integer;
procedure calc (Item : in Integer) is
New_Value : Integer;
begin
Put ("The value of the index is now");
Put (Item);
New_Line;
New_Value := (Item - 1);
if New_Value > 0 then
calc (New_Value);
end if;
end calc;
begin
Get (Index);
Get (Mindex);
calc (Index);
New_Line;
calc (Mindex);
end Add;
A factorial keeps chaining multiplication with each decreasing value: 5! = 5 * 4 * 3 * 2 * 1 = 120. In order to do the recursion, you'll need to have two cases inside your recursive function: If your value is above 1, then multiply that value with the next smallest number. That's the recursive part where you will call Factorial(N-1) inside of Factorial(N). Otherwise just return 1 (factorial of 0 is 1 mathematically, so both 1! and 0! equal 1).
The way this works in Ada is:
function Factorial(Value : Natural) return Natural is
begin
if Value > 1 then
-- Keep chaining the multiplication with recursion
return Value * Factorial(Value - 1);
else
-- No need to chain as the result is always 1
return 1;
end if;
end Factorial;
You can then call that Factorial function on each of your numbers and add the results.
I get an 16 Bit integer from C. This integer consists of 16 flags.
How can I convert this integer in a record of 16 booleans?
Thanks!
type Flags is record
Flag1 : Boolean;
Flag2 : Boolean;
- ...
Flag15 : Boolean;
end record;
for Flags use record
Flag1 at 0 range 0 .. 0;
Flag2 at 0 range 1 .. 1;
-- ...
Flag15 at 0 range 15 .. 15;
end record;
for Flags'Size use 16;
-- This is vital, because normally, records are passed by-reference in Ada.
-- However, as we use this type with C, it has to be passed by value.
-- C_Pass_By_Copy was introduced in GNAT and is part of the language since Ada 2005.
pragma Convention (C_Pass_By_Copy, Flags);
You can use this type directly in the declaration of the imported C function instad of the C integer type.
You can just simply perform 16 right bit shifts and bitwise AND the result with 1 to determine whether or not a bit/flag is set. Here's an example (I'm hoping this isn't homework):
#include <stdio.h>
#include <stdint.h>
typedef unsigned char BOOL;
int main(void)
{
unsigned i;
uint16_t flags = 0x6E8B; /* 0b0110111010001011 */
BOOL arr[16];
for (i = 0; i < 16; i++) {
arr[i] = (flags >> i) & 1;
printf("flag %u: %u\n", i+1, arr[i]);
}
return 0;
}
arr[0] will contain the least significant bit, and arr[15] the most significant.
Output:
flag 1: 1
flag 2: 1
flag 3: 0
flag 4: 1
flag 5: 0
flag 6: 0
flag 7: 0
flag 8: 1
flag 9: 0
flag 10: 1
flag 11: 1
flag 12: 1
flag 13: 0
flag 14: 1
flag 15: 1
flag 16: 0
In Ada, you can usually declare an imported function to take parameters or return values of the type you want, rather than a C-equivalent type which you then have to convert.
So, here, you want
type Flags is array (0 .. 15) of Boolean;
for Flags'Component_Size use 1;
for Flags'Size use 16;
pragma Convention (C, Flags);
and you can declare your function as
function Get_Flags return Flags;
pragma Import (C, Get_Flags, “get_flags");
which with
unsigned short get_flags(void) {
return 0x6e8b;
}
and a simple harness gave me
flag 0 is TRUE
flag 1 is TRUE
flag 2 is FALSE
flag 3 is TRUE
flag 4 is FALSE
flag 5 is FALSE
flag 6 is FALSE
flag 7 is TRUE
flag 8 is FALSE
flag 9 is TRUE
flag 10 is TRUE
flag 11 is TRUE
flag 12 is FALSE
flag 13 is TRUE
flag 14 is TRUE
flag 15 is FALSE
As Bo Persson noted, this is fine so long as your code only needs to run on a little-endian machine. If you want it to run on a SPARC or a Powerbook, it’s probably best to use trashgod’s suggestion;
subtype Flags is Interfaces.C.unsigned_short;
use type Flags;
function Get_Flags return Flags;
pragma Import (C, Get_Flags, "get_flags");
and then, probably, name your flag bits (with something more meaningful!)
Flag_3 : constant Flags := 2#0000_0000_0000_1000#;
or (probably more like the C)
Flag_4 : constant Flags := 2 ** 4;
and then check
(Get_Flags and Flag_3) /= 0
In Ada, a modular type allows logical operations to access a value as a bit set. Introduced in Ada 95, an overview may be found in the Ada 95 Rationale, §3.3.2 Modular Types. Depending on implementation, the pre-defined type Interfaces.C.unsigned_short my be a convenient choice for obtaining the value from C.
You can also use overlaying to achieve the desired result; let's assume that these booleans are all meaningful and strictly boolean (i.e. nothing that's an enumeration).
First you need to define your record; I'm going to be using a single Nybble to illustrate, but the principle is applicable. The Nybble is the old DOS attributes: reading (visibility-wise; should be Is_Hidden, in retrospect), write, archive, and system.
Type Nyble_Data is mod 2**4;
For Nyble_Data'Size use 4;
Type Data_Record is record
Can_Read, Can_Write, Is_Archived, Is_System : Boolean:= False;
end record;
-- Ensure 4 bits used.
pragma Pack (Data_Record);
For Data_Record'Size use 4;
-- Specify Layout.
For Data_Record use
record
Can_Read at 0 range 0..0;
Can_Write at 0 range 1..1;
Is_Archived at 0 range 2..2;
Is_System at 0 range 3..3;
end record;
-- This is where the magic occurs.
Function Convert( Data : In Nyble_Data ) Return Data_Record is
Result : Data_Record;
For Result'Address use Data'Address;
Pragma Import( Convention => Ada, Entity => Result );
Pragma Inline( Convert );
begin
Return Result;
end Convert;
-- Test variables.
Input : Nyble_Data:= 5;
Output : Data_Record:= Convert(Input);
-- Display the record.
Procedure Put( Data : In Data_Record ) is
Use Ada.Text_IO;
begin
Put_Line( "Read: " & ASCII.HT & Boolean'Image(Data.Can_Read) );
Put_Line( "Write: " & ASCII.HT & Boolean'Image(Data.Can_Write) );
Put_Line( "Archive:" & ASCII.HT & Boolean'Image(Data.Is_Archived) );
Put_Line( "System: " & ASCII.HT & Boolean'Image(Data.Is_System) );
end Put;
You can use a union containing a short int (or a int_16) and a bit field:
union UMyFlags {
short n;
struct {
flag_1 : 1;
flag_2 : 1;
// other flags ...
} flags;
};
However, because of byte ordering, your code will not be portable on every platform.