4
\$\begingroup\$

I have written a change calculator using Ada. when the user inputs an amount of money it returns a list of the coins and bills needed to create that total. It starts off by trying to use the largest money types then tries smaller ones.

I am still learning how to use Ada and would like to know how i can make better use of the language features. Am i using the right data types, is there a way to make the change calculation loop more readable?

with Ada.Text_IO;
with Ada.Float_Text_IO;
with Ada.IO_Exceptions;
with Ada.Integer_Text_IO;
use Ada;
procedure Change_Calculator is
 type Money is delta 0.01 digits 10;
 Input_Amount : Money := 0.0;
 package Money_IO is new Text_IO.Decimal_IO(Money);
 type Currency_Denomination is record
 Name : String(1..10);
 Value : Money;
 end record;
 Currency_Names : array (1..10) of Currency_Denomination;
 Currency_Counts : array (1..10) of Integer := (others=>0);
 Currency_Index : Integer range 1..10;
 procedure Get_Money_Prompt(Amount: out Money) is
 Response : String(1..20);
 Last : Natural;
 begin
 loop
 declare
 begin
 Text_IO.Put("amount: ");
 Text_IO.Flush;
 Text_IO.Get_Line(Response, Last);
 -- try to convert string input to money type
 Amount := Money'Value(Response(1 .. Last));
 -- quit the loop if the money converted -- '
 exit;
 exception
 when Constraint_Error =>
 Text_IO.Put_Line("ERROR: bad money format");
 end;
 end loop;
 end Get_Money_Prompt;
begin
 Currency_Names := (("Penny ", 0.01),
 ("Nickle ", 0.05),
 ("Dime ", 0.10),
 ("Quarter ", 0.25),
 ("Dollar ", 1.00),
 ("5 Dollar ", 5.00),
 ("10 Dollar ", 10.00),
 ("20 Dollar ", 20.00),
 ("50 Dollar ", 50.00),
 ("100 Dollar", 100.00));
 -- read money amount from the user
 Get_Money_Prompt(Input_Amount);
 -- calculate needed currency
 for I in Currency_Names'Range loop
 -- calculate inverse of index to count backwords
 Currency_Index := (Currency_Names'Length-I)+1;
 while Input_Amount >= Currency_Names(Currency_Index).Value loop
 Input_Amount := Input_Amount - Currency_Names(Currency_Index).Value;
 -- increment currency useage in array
 Currency_Counts(I) := Currency_Counts(I) + 1;
 end loop;
 end loop;
 -- display needed currency
 for I in Currency_Counts'Range loop
 Currency_Index := (Currency_Names'Length-I)+1;
 -- do not display unused currency
 if Currency_Counts(Currency_Index) /= 0 then
 Text_IO.Put(Currency_Names(I).Name & " ");
 Integer_Text_IO.Put(Currency_Counts(Currency_Index));
 Text_IO.New_Line;
 end if;
 end loop;
end Change_Calculator;
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Oct 2, 2015 at 22:42
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Currency_Names, Currency_Counts and Currency_Index all use the same range, so it is better to declare a ranged type (or a subtype):

 type Index is range 1..10;
 Currency_Names : array (Index) of Currency_Denomination;
 Currency_Counts : array (Index) of Integer := (others=>0);
 Currency_Index : Index;

To loop backwards, it is better to use the reverse keyword:

 -- calculate needed currency
 for I in reverse Currency_Names'Range loop
 while Input_Amount >= Currency_Names(I).Value loop
 Input_Amount := Input_Amount - Currency_Names(I).Value;
 -- increment currency useage in array
 Currency_Counts(I) := Currency_Counts(I) + 1;
 end loop;
 end loop;
 -- display needed currency
 for I in Currency_Counts'Range loop
 -- do not display unused currency
 if Currency_Counts(I) /= 0 then
 Text_IO.Put(Currency_Names(I).Name & " ");
 Integer_Text_IO.Put(Currency_Counts(I));
 Text_IO.New_Line;
 end if;
 end loop;

A nice side-effect is that the index of Currency_Counts will now correspond to the index of Currency_Names, no need to calculate the index anymore, and the Currency_Index variable is no longer needed.

answered Oct 9, 2015 at 14:43
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.