patternMinor
Calculating change in Ada
Viewed 0 times
adacalculatingchange
Problem
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
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
Solution
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.Code Snippets
type Index is range 1..10;
Currency_Names : array (Index) of Currency_Denomination;
Currency_Counts : array (Index) of Integer := (others=>0);
Currency_Index : Index;-- 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;Context
StackExchange Code Review Q#106406, answer score: 4
Revisions (0)
No revisions yet.