<--Last Chapter | Table of Contents | Next Chapter--> |
Ada Package
|
Description
|
C Equivalent
|
Ada.Characters.Handling
|
Character operations
|
Strings.h?
|
Ada.Strings.Fixed
|
Ada string operations
|
Strings.h
|
Ada.Strings.Bounded
|
Bounded strings and operations
|
- |
Ada.Strings.Unbounded
|
Unbounded strings and operations
|
- |
Gnat.Case_Util
|
Just case conversions
|
- |
Ada.Strings.Unbounded.Text_IO
|
Text_IO for Unbounded Strings | - |
Unbounded strings are strings that can be of any size.
They are typically implemented by dynamic allocation, which makes
them slow, but they don't waste memory the way bounded strings do
and there's no risk over a string overflow. The standard Ada
library Ada.Strings.Unbounded contains the definition of
unbounded strings and operations on them, including a function to
convert an unbounded string to a fixed string.
C: Unbounded strings are not exactly the
same as C strings. For one thing, unbounded strings don't end in
null characters. C String support is in the packages
Interfaces.C.
|
For string handling capabilities, you need to use a package. The
standard Ada library Ada.Strings.Fixed contains operations
for fixed strings, including extracting substrings, mapping
characters from one set to another (for example, upper to lower
case), and string searching. There is also an
Ada.Strings.Unbounded package containing the same subprograms
for unbounded strings, and likewise an Ada.Strings.Bounded
for bounded strings.
The rich get richer
The length of the string is 19
If we append, ' but not happier', the string is
The rich get richer but not happier
The ampersand will work as well: The rich get richer but not happier
The fifth character is r
Replacing the 20th character, we get
Replacing the first 'rich' with 'RICH' we get
The following sample program demonstrates the uses of case_util:
with text_io, gnat.case_util;
The choice of string type to use depends on functionality and performance. Here's a chart showing a series of tests using different string types. The tests were run on my Pentium II 350 MHz.
Fixed String (2K) Bounded String Unbounded (2K) Character Append 0.01 s 72.8 s 16.0 s Concat.Two Strings 14.9 s 22.5 s 76.4 s Equality 0.18 s 0.09 0.08 s 0.43 s 0.24 s Conversion to 70.0 s 12.4 s Fixed - 71.8 s 13.6 s Insert/Delete 11.8 s 30.6 s 115.2 s 15.2 s Replace Character 0.3 s 0.7 s 0.9 s Determining Length 0.3 s 0.4 s 0.6 s Duplication 3.1 s 1.4 s 2.1 s
This is a very informal benchmark and is intended only to demonstrate the kinds of problems associated with different strings. The actual performance will depend on the length of the strings, the optimization in the packages and nature of the string operations. This case used 2K strings (where applicable) and each test was performed 1 million times.
Fixed strings are almost always faster, but they often involve writing work-arounds due to the possibility of constraint errors. Unbounded strings have no constraints but almost always the slower than either fixed or bounded strings. Bounded strings offer a balance between convenience and performance and are the fastest for copying values.
Text_IO file operations are very limited and are only intended for quick and dirty programs. There are other libraries for more extensive file operations, such as Ada.Sequential_IO and Ada.Direct_IO.
There is also a subpackage for displaying formatted text, such as columns of numbers.
You can open an existing sequential IO file, or you can create a new one. When you open or create a file, you have to indicate what file mode you'll be using. "In" mode files can only be read. "Out" mode files can only be written to. "Append" is like out mode except that records are added to the end of an existing file.
The reset procedure changes to a new mode and repositions your program accordingly to the end or beginning of the file.
When you are finished with a sequential file, you can either close it or delete it if you don't need it again.
Because there is no way of knowing how many records are remaining in the file, there is a function called End_of_File that you can check after each read to see if the last item has been read. You can only use End_of_File in In mode--it makes no sense to use it in Out or Append modes since you always write at the end of the file.
The following program writes a couple of customer records to a sequential file and reads them back again:
with Ada.Text_IO, Ada.Sequential_IO, Ada.IO_Exceptions; use Ada.Text_IO; procedure sequentio is -- Ada.Sequential_IO example type aCustomer is record name : string(1..40); amountOwing : float := 0.0; end record; -- a customer record with two fields package aCustomerFile is new Ada.Sequential_IO( aCustomer ); use aCustomerFile; -- instantiate a new package for sequential IO on a file of -- customer records CustomerFile : aCustomerFile.File_Type; -- our customer file -- use "aCustomerFile" because Text_IO and Sequential_IO have File_Type cr : aCustomer; begin Put_Line( "This is a Ada.Sequential_IO example" ); New_Line; -- create the file Create( CustomerFile, Mode => Out_File, Name => "customer.seq" ); -- display some statistics Put_Line( "We created the file " & Name( CustomerFile ) ); Put_Line( "We're currently using " & Mode( CustomerFile )'img & " mode" ); if Is_Open( CustomerFile ) then Put_Line( "The file is open" ); else Put_Line( "The file isn't open" ); end if; New_Line; -- write the first record cr.name := "Tokyo Book Distributors "; Write( CustomerFile, cr ); Put_Line( "Writing " & cr.name ); -- write another record cr.name := "General Pizza Inc. "; Write( CustomerFile, cr ); Put_Line( "Writing " & cr.name ); Put_Line( "End_of_File not allowed on Out files" ); begin if End_Of_File( CustomerFile ) then Put_Line( "We are at the end of the file" ); else Put_Line( "We aren't at the end of the file" ); end if; exception when Ada.IO_Exceptions.Mode_Error => Put_Line( Standard_Error, "End_of_File caused Ada.IO.Exceptions.Mode_Error" ); when others => Put_Line( Standard_Error, "Unexpected exception occurred" ); end; New_Line; -- change modes using Reset Put_Line( "Reset can change the file mode" ); Put_Line( "Changing to In_File mode" ); Reset( CustomerFile, In_File ); -- read first record Put_Line( "Reading the next customer" ); Read( CustomerFile, cr ); Put_Line( "Read " & cr.name ); New_Line; -- read second record Put_Line( "Reading the next customer" ); Read( CustomerFile, cr ); Put_Line( "Read " & cr.name ); New_Line; -- check the end of the file Put_Line( "End_of_File works on In files" ); if End_Of_File( CustomerFile ) then Put_Line( "We are at the end of the file" ); else Put_Line( "We aren't at the end of the file" ); end if; New_Line; Put_Line( "Closing file" ); Close( CustomerFile ); end sequentio;
This is a Ada.Sequential_IO example We created the file /home/ken/ada/trials/customer.seq We're currently using OUT_FILE mode The file is open Writing Tokyo Book Distributors Writing General Pizza Inc. End_of_File not allowed on Out files End_of_File caused Ada.IO.Exceptions.Mode_Error Reset can change the file mode Changing to In_File mode Reading the next customer Read Tokyo Book Distributors Reading the next customer Read General Pizza Inc. End_of_File works on In files We are at the end of the file Closing file
[Form not covered--KB]
A telephone book, for example, can be considered one large table. Each row contains information about a different person. Each row is subdivided into columns of names, addresses and phone numbers.
Although you could represent a database table using a sequential IO file, it would be very difficult to use. To look up the 1000th entry in the file, you would have to read through the first 999 entries.
The Ada equivalent to a database table is called a direct IO file. Some languages refer to this kind of file as a "random access" file. A direct IO file is called "direct" because you can move directly to any row in the file without having to read any other rows.
The rows in a direct IO file are typically represented by records (athough they can be any data of a known length) and the columns are the fields in the records. Direct IO files can also use variant records--Ada will ensure there is enough space in each entry for the largest variation.
You can open an existing direct IO file, or you can create a new one. When you open or create a file, you have to indicate what file mode you'll be using. "In" mode files can only be read. "Out" mode files can only be rewritten. Unlike sequential IO files, there is also an "In Out" mode which allows you to both read and write records. This is the most common mode for accessing direct IO files.
If you move to a position beyond the end of the file, such as trying to write to row 100 when there are only 50 rows, the other unused rows will be created and filled with zero bytes--ASCII.NUL in characters or strings, 0 in integers and long_integers, and so forth. The only way to shorten a direct IO file is to create a new one, delete the original and copy the new one in place of the original.
There are several useful functions for direct IO files:
Is_Open
is true if the file has been openedEnd_Of_File
is true if you have read the last
record in the file. (This is unavailable in out mode.)Name
is the path of the fileMode
is the current file modeSize
is the number of rows in the fileIndex
is the number of the current rowThe following example program reads and writes customer information using the Ada.Direct_IO package.
with Ada.Text_IO, Ada.Direct_IO, Ada.IO_Exceptions; use Ada.Text_IO; procedure dirio is -- Ada.Direct_IO example type aCustomer is record name : string(1..40); amountOwing : float; end record; -- a customer record with two fields package aCustomerFile is new Ada.Direct_IO( aCustomer ); use aCustomerFile; -- instantiate a new package for direct IO on a file of -- customer records CustomerFile : aCustomerFile.File_Type; -- our customer file -- use "aCustomerFile" because Text_IO and Direct_IO have File_Type cr : aCustomer; begin Put_Line( "This is a Ada.Direct_IO example" ); New_Line; -- create the file Create( CustomerFile, Mode => Out_File, Name => "customer.dir" ); -- display some statistics Put_Line( "We created the file " & Name( CustomerFile ) ); Put_Line( "We're currently using " & Mode( CustomerFile )'img & " mode" ); Put_Line( "There are" & Size( CustomerFile )'img & " records" ); Put_Line( "We are on row " & Index( CustomerFile )'img ); if Is_Open( CustomerFile ) then Put_Line( "The file is open" ); else Put_Line( "The file isn't open" ); end if; New_Line; -- write the first record cr.name := "Midville Electric "; Write( CustomerFile, cr ); Put_Line( "Writing " & cr.name ); Put_Line( "There are" & Size( CustomerFile )'img & " records" ); Put_Line( "We are on row " & Index( CustomerFile )'img ); New_Line; -- write the next record on row 7 cr.name := "New York Distributors "; Write( CustomerFile, cr, To => 7 ); Put_Line( "Writing " & cr.name & " to row 7" ); Put_Line( "There are" & Size( CustomerFile )'img & " records" ); Put_Line( "We are on row " & Index( CustomerFile )'img ); Put_Line( "End_of_File not allowed on In files" ); begin if End_Of_File( CustomerFile ) then Put_Line( "We are at the end of the file" ); else Put_Line( "We aren't at the end of the file" ); end if; exception when Ada.IO_Exceptions.Mode_Error => Put_Line( Standard_Error, "End_of_File caused Ada.IO_Exceptions.Mode_Error" ); when others => Put_Line( Standard_Error, "Unexpected exception occurred" ); end; New_Line; -- change modes using Reset Put_Line( "Reset can change the file mode" ); Put_Line( "Changing to InOut_File mode" ); Reset( CustomerFile, InOut_File ); -- read first record Put_Line( "Reading the next customer" ); Read( CustomerFile, cr ); Put_Line( "Read " & cr.name ); New_Line; -- read second (undefined record) Put_Line( "Reading from row 2" ); Read( CustomerFile, cr ); Put_Line( "Read " & cr.name ); New_Line; -- read 7th row Put_Line( "Reading from row 7" ); Read( CustomerFile, cr, From => 7 ); Put_Line( "Read " & cr.name ); New_Line; -- check the end of the file Put_Line( "End_of_File works on InOut files" ); if End_Of_File( CustomerFile ) then Put_Line( "We are at the end of the file" ); else Put_Line( "We aren't at the end of the file" ); end if; New_Line; Put_Line( "Closing file" ); Close( CustomerFile ); end dirio;
This is a Ada.Direct_IO example We created the file /home/ada/customer.dir We're currently using OUT_FILE mode There are 0 records We are on row 1 The file is open Writing Midville Electric There are 1 records We are on row 2 Writing New York Distributors to row 7 There are 7 records We are on row 8 End_of_File not allowed on In files End_of_File caused Ada.IO_Exceptions.Mode_Error Reset can change the file mode Changing to InOut_File mode Reading the next customer Read Midville Electric Reading from row 2 Read Reading from row 7 Read New York Distributors End_of_File works on InOut files We are at the end of the file Closing file
Note: In this example, reading from the unassigned second record put a row of 40 ASCII.NUL characters on the screen. Because these are non-printable characters, nothing is visible in the results. |
[What about objects? How are tags treated? --KB]
Direct_IO files are suitable for small database tables. If you need to work with large amounts of data, you should consider installing one of the free Linux databases (such as PostgreSQL or mySQL) and using them to store and retrieve your data. This is discussed in upcoming chapters.
Alternately, you can write your own database package using a the Linux kernel. seqio, a sequential IO package, is developed in chapter 16.
The Ada.Text_IO.Editing provides formatted output. The string template is called a picture. The picture can contain the following symbols.
A PICTURE_ERROR is raised if there is a mistake in the layout. A LAYOUT_ERROR is raised if the layout can't be used with a particular value. Using a negative number without specifying a format symbol that allows negative numbers causes a LAYOUT_ERROR.
Before using Text_IO.Editing, the internal generaic package Decimal_Output must be instantiated for a particular numeric type. Only decimal types are allowed.
type money is delta 0.01 digits 18; package formatted_io is new ada.text_io.editing.decimal_output( money );
To_Picture converts a string to a picture type. Pic_String returns the string of the picture type.
p : picture := To_Picture( "###9.99" ); s : string := Pic_String( p );
Valid returns true if a string is a valid picture. When Blank_When_Zero parameter is true, a zero represented as an empty string is allowed. By default, the picture string must show something for a zero. Blank_When_Zero can also be used with To_Picture.
if not Valid( "####9.99" ) then Put_Line( Standard_Error, "This is a bad picture string" ); end if;
Put displays the formatted decimal value. There is also an Image function that returns the results as a string instead of displaying it on the screen. Length returns the length of the formatted output. There is no Put_Line.
Put( 455.32, pic ); str := Image( 455.32, pic ); Put( str, 455.32, pic );
Here is an larger example:
with ada.text_io.editing; use ada.text_io; use ada.text_io.editing; procedure formatted is type money is delta 0.001 digits 18; package formatted_io is new ada.text_io.editing.decimal_output( money ); use formatted_io; procedure ShowValues( s : string ) is begin put( " 0.0 and " &s & " => " ); put( 0.0, To_Picture( s ) ); new_line; put( " 75.12 and " &s & " => " ); put( 75.12, To_Picture( s ) ); new_line; put( "-75.12 and " &s & " => " ); begin put( -75.12, To_Picture( s ) ); exception when others => put( "LAYOUT_ERROR" ); end; new_line; end ShowValues; begin put_line( "This is an example of Formatted Output" ); put_line( "--------------------------------------" ); new_line; put_line( "Default currency symbol is " & Default_Currency ); put_line( "Default fill character is '" & Default_Fill & "'" ); put_line( "Default separator character is '" & Default_Separator & "'" ); put_line( "Default radix mark is '" & Default_Radix_Mark & "'" ); new_line; ShowValues( "99999.99" ); New_Line; ShowValues( "ZZZZ9.99" ); New_Line; ShowValues( "****9.99" ); New_Line; ShowValues( "-$$$9.99" ); New_Line; ShowValues( "+###9.99" ); New_Line; ShowValues( "<###9.99>" ); New_Line; end formatted;
This is an example of Formatted Output -------------------------------------- Default currency symbol is $ Default fill character is ' ' Default separator character is ',' Default radix mark is '.' 0.0 and ZZZZ9.99 => 0.00 75.12 and ZZZZ9.99 => 75.12 -75.12 and ZZZZ9.99 => LAYOUT_ERROR 0.0 and -9999.99 => 0000.00 75.12 and -9999.99 => 0075.12 -75.12 and -9999.99 => -0075.12 0.0 and ****9.99 => ****0.00 75.12 and ****9.99 => ***75.12 -75.12 and ****9.99 => LAYOUT_ERROR 0.0 and -$$$9.99 => $0.00 75.12 and -$$$9.99 => $75.12 -75.12 and -$$$9.99 => - $75.12 0.0 and +###9.99 => + $0.00 75.12 and +###9.99 => + $75.12 -75.12 and +###9.99 => - $75.12 0.0 and <###9.99> => $0.00 75.12 and <###9.99> => $75.12 -75.12 and <###9.99> => ( $75.12)
Put has many parameters used to override default values.
There is also a Wide_Text_IO.Editing for wide string.
Calendar is the standard Ada package for telling time. You can get the current time, compare time values, do time arithmetic and comparisons. There is also a GNAT.Calendar package which extends the Ada.Caledar package with days of the week, second duration, and other features.
Table: North American Federal Holidays and Celebrations
Work schedules (not including small retail stores) often affected by these holidays.
North American Banking (and postal) Holidays include Easter Monday and Victoria Day (Canada).
Daylight Savings time begins, first Sunday in April (but not in Arizona, Hawaii, and parts of southern Indiana).
Daylight Savings Time ends, last Sunday in October (but not in Arizona, Hawaii, and parts of southern Indiana).
Table:Other Widely Celebrated North American Observances
with text_io, calender; use calender; procedure caldemo is Year : Year_Number; Month : Month_Number; Day : Day_Number; Seconds : Day_Duration; Christmas94 : time; begin Text_IO.Put_Line( "A simple calendar example" ); Text_IO.New_Line; Split( Clock, Year, Month, Day, Seconds ); Text_IO.Put_Line( "The current date is" & Year'img & "/" & Month'img & "/" & Day'img ); Text_IO.Put_Line( "It's" & seconds'img & " seconds into the day" ); Text_IO.New_Line; Christmas94 := Time_Of( 1994, 12, 25 ); if Christmas94 < Clock then Text_IO.Put_Line( "It's after Christmas 1994" ); else Text_IO.Put_Line( "It's before Christmas 1994" ); end if; Text_IO.New_Line; Split( Clock+12.5, Year, Month, Day, Seconds ); Text_IO.Put_Line( "In 12.5 seconds it will be " & Year'img & "/" & Month'img & "/" & Day'img ); Text_IO.Put_Line( "And" & seconds'img & " seconds into the day" ); end caldemo;
A simple calendar example The current date is 1998/ 12/ 17 It's 59775.185023000 seconds into the day It's after Christmas 1994 In 12.5 seconds it will be 1998/ 12/ 17 And 59787.686581000 seconds into the day
The GNAT.Calendar.Time_IO package will write a time value according to a format string, similar to the Linux strftime function.
Easter is one of the hardest holidays to calculate. The following is a program to calculate the date of Easter Sunday:
[This should be rewritten for Ada.Calender -- KB]with Ada.Text_IO; use Ada.Text_IO; procedure easter is procedure findEaster( year : integer; easter_month, easter_day : out integer ) is -- based on the public domain algorithm -- by Ed Bernal a,b,c,e,g,h,i,k,u,x,z : integer; begin -- -- "Gauss' famous algorithm (I don't know how or why it works, -- so there's no commenting)" -- Ed Bernal -- a := year mod 19; b := year / 100; c := year rem 100; z := b / 4; e := b rem 4; g := (8*b + 13) / 25; h := (19*a + b - z - g + 15) rem 30; u := (a + 11*h) / 319; i := c / 4; k := c rem 4; x := (2*e + 2*i - k - h + u + 32) rem 7; easter_month := (h-u+x+90) / 25; easter_day := (h-u+x + easter_month +19) rem 32; end findEaster; month, day : integer; begin findEaster( 2000, month, day ); Put( "Easter Sunday 2000 is month " & month'img ); Put_Line( " and day " & day'img ); end easter;
Easter Sunday 2000 is month 4 and day 23
with text_io, ada.tags;
procedure t is
type ParentRec is tagged record
type ChildRec is new ParentRec with record
child : ChildRec;
begin
if child in ParentRec'class then
Working with Tagged Record Tags:
ParentRec has an external tag of T.PARENTREC
child (a child rec) is in ParentRec'class
[expand and give example program]
Gnat 3.11: This version of gnat adds remove and
iterator subprograms for hash tables.
|
The following is an example using a hash table of integers.
with text_io, gnat.htable;
procedure hashtest is
-- First, define the items required by gnat.htable
type HashTableIndex is newinteger range 1..200;
function HashOf( he : HashElement ) return HashTableIndex is
-- OK, instantiate the package
package IntTable is new gnat.htable.simple_htable(
begin
IntTable.Set( 1, 1 );
Pulling 1 from the hash table = 1
[Could use more realistic example--KB]
The first, gnat.bubble_sort_g, is a generic. You provide the package with a procedure to move data in the array and a function to check for one value being less than another. The instantiation provides a sort procedure.
with text_io, gnat.bubble_sort_g;
procedure bubble1 is
-- Our table to sort
type IntegerTable is array( 0..5 ) of integer;
-- Define the items required by a generic gnat bubble sort
procedure MoveIntegers( From, To : natural ) is
function CompareIntegers( left, right : natural ) return boolean is
-- OK, instantiate the package
package IntSort is new gnat.bubble_sort_g(
procedure ShowTable is
begin
0 = 0
The sorted table is:
0 = 13
The second, gnat.bubble_sort_a uses callbacks instead of a generic package. Use this package if you want to conserve memory by avoiding a lot of instantiations of the generic bubble_sort_g. Remember that callbacks must be global, so we can't simple pass the local subprograms we created in bubble1. This time we must store the array and subprograms in a separate package.
with text_io, gnat.bubble_sort_a, inttable;
procedure bubble2 is
package inttable is
-- Our table to sort
type IntegerTable is array( 0..5 ) of integer;
-- Define the items required by a callback gnat bubble sort
procedure MoveIntegers( From, To : natural );
function CompareIntegers( left, right : natural ) return boolean;
procedure ShowTable;
end inttable;
with text_io;
package body inttable is
procedure MoveIntegers( From, To : natural ) is
function CompareIntegers( left, right : natural ) return boolean is
procedure ShowTable is
end inttable;
0 = 0
The sorted table is:
0 = 13
The heap sort package works identically, with both generic (heap_sort_g) and callback (heap_sort_a) versions as well. Heap sorts are better suited to large amounts of data. Here's the callback version using the same inttable package we used above.
with text_io, gnat.heap_sort_a, p;
procedure heaptest is
[this wasn't corrupted before—MS Word bug?]
Using the package is a two step process. First, you must compile the expression using the Compile function. Then, you check for a string that matches the expression using the Match function.
The following program demonstrates the Regexp package.
with Ada.Text_IO, GNAT.Regexp;
procedure regex is
procedure TestMatch( re : Regexp; s : string ) is
Criteria : Regexp;
begin
-- UNIX Regular Expressions
Put_Line( "A 'globbing pattern' is a UNIX shell-style pattern matching" );
-- BNF Expressions
Put_Line( "A non-globbing pattern is a BNF pattern, as used in the Ada" );
A 'globbing pattern' is a UNIX shell-style pattern matching
accounting matches the expression
A non-globbing pattern is a BNF pattern, as used in the Ada
accounting matches the expression
The second Gnat pattern matching package is "Regpat" which interprets full UNIX V7 regular expressions as defined in the "man regexp" Linux man page. Don't be confused by the naming conventions: the Regexp package does not do Linux regular expressions.
GLADE is built into the ALT version of GNAT.
To install GLADE, unpack it and type "configure" and "make install".
GLADE works on partitions, programs designed to run on other computers. Each partition has a channel between itself and another partition. Of course, the partitions can also run concurrently on one computer. You describe the partitions and channels using an Ada-like language called Garlic.
GLADE uses rsh to start partitions, so make sure you don't run the programs under the root login since root is not allowed to run programs via rsh.
[KB: I could install and compile programs with glade, but the communication wasn't working…error in my networking setup or did I not install it properly?]
Type | Ada Package | Description |
Generic | Ada.Numerics.Generic_Elementary_Functions | basic math for floating point numbers |
Short_Float | Ada.Numerics.Short_Elementary_Functions | basic math for short_float type |
Float | Ada.Numerics.Elementary_Functions | basic math for float type |
Long_Float | Ada.Numerics.Long_Elementary_Functions | basic math for long_float type |
Long_Long_Float | Ada.Numerics.Long_Log_Elementary_Functions | basic math for long_long_float type |
Sooner or later, you will ask the question, "So, how do I compute the cosine of a number?" The answer found is the Ada.Numerics.Generic_Elementary_Functions package. This package with the unusually long name is the basic floating point math package. This is a generic package that you instantiate for a particular floating point type. For example, to set up the package for a custom floating point type called "percent",
with Ada.Numerics.Generic_Elementary_Functions; type percent is new float range 0.0..1.0; package percentMath is new Ada.Numerics.Generic_Elementary_Functions( percent ); use percentMath;
The "use percentMath" statement saves us from typing "percentMath." before every function we use.
With percentMath instantiated, we can now perform basic floating point math functions such as
Put_Line( "20% to the power of 3 is" & percent'image( 0.2**3.0 ) );
As shown in the table at the start of this section, elementary function packages for the basic floating point types are included with Gnat.
The elementary package includes:
Function | Description |
Sqrt( x ) | Square Root |
Log( x ) | Natural Logarithm (ln in some other languages) |
Log( x, b ) | Logarithm to base b |
Exp( x ) | Raise e by power x |
** | Power operator |
Sin( x ) | Sine for x radians |
Sin( x, c ) | Sine for x where cycle range is c (eg. 360 for degrees) |
Cos( x ) | Cosine for x radians |
Cos( x, c ) | Cosine for x where cycle range is c |
Tan( x ) | Tangent for x radians |
Tan( x, c ) | Tangent for x where cycle range is c |
There are corresponding functions for arctan, arccot, sinh, cosh, tanh, coth, arccosh, arctanh, artcoth.
Here's an example using the built-in functions for the float type, and creating our own functions for our own percent type:
with Ada.Text_IO, Ada.Numerics.Elementary_Functions, Ada.Numerics.Generic_Elementary_Functions; use Ada.Text_IO, Ada.Numerics.Elementary_Functions; procedure floatmath is type percent is new float range 0.0..1.0; package percentMath is new Ada.Numerics.Generic_Elementary_Functions( percent ); use percentMath; half : percent := 0.5; begin Put_Line( "Here's some floating point math!" ); New_Line; Put_Line( "4.0 to the power 3.0 is" & float'image( 4.0 ** 3.0 ) ); Put_Line( "The sine of 0.4 radians is" & float'image( sin( 0.4 ) ) ); Put_Line( "The cosine of 180 degrees is" & float'image( sin( 180.0, 360.0 ) ) ); Put_Line( "The square root of 81 is" & float'image( sqrt( 81.0 ) ) ); Put_Line( "50% squared is" & percent'image( half ** 2.0 ) ); end floatmath;
Here's some floating point math! 4.0 to the power 3.0 is 6.40000E+01 The sine of 0.4 radians is 3.89418E-01 The cosine of 180 degrees is 0.00000E+00 The square root of 81 is 9.00000E+00 50% squared is 2.50000E-01
When you work with floating point subprograms in libraries outside of Ada, there's a chance that the library will change the floating point arithmetic settings for your CPU. When this happens, use the GNAT.Float_Control package to change your CPU back to GNAT's preferred defaults. There is only one subprogram in this package: reset.
If you are interested in integer operations not covered by the built-in Ada features, the Interfaces package (the package used to interface Ada to other languages) defines several bit-shifting functions. In order to use these functions, you'll need to convert (or derrive) your integer values to one of Interfaces' integer types:
Function | Description |
Rotate_Left | Rotate bits in integer types leftward |
Rotate_Right | Rotate bits in integer types rightward |
Shift_Left | Shift bits in integer types leftward |
Shift_Right | Shift bits in integer types rightward |
Shift_Right_Arithmetic | Arithmetic shift bits in integer types rightward |
C: Shift_Left is the equivalent of the C << operator. Shift_Right is the equivalent of the >> operator. |
In Gnat, bit-shifting operations are intrinsic. That is, they act as built-in functions and execute quickly.
Here is an example of shifting integer values.
with Ada.Text_IO, Interfaces; use Ada.Text_IO, Interfaces; procedure shiftMath is six : unsigned_64 := 6; begin Put_Line( "Time to do a little bit shifting" ); New_Line; Put_Line( "Our integer is" & six'img ); Put_Line( "In binary, this is" & six'img ); Put_Line( "Shifted left once is" & Shift_Left( six, 1 )'img ); Put_Line( "Shifted left twice is" & Shift_Left( six, 2 )'img ); Put_Line( "Shifted right once is" & Shift_Right( six, 1 )'img ); Put_Line( "Arithmetic Shifted right once is" & Shift_Right_Arithmetic( six, 1 )'img ); end shiftMath;
Time to do a little bit shifting Our integer is 6 In binary, this is 6 Shifted left once is 12 Shifted left twice is 24 Shifted right once is 3 Arithmetic Shifted right once is 3
Gnat includes packages for working with exceptions. Using these packages, you can add a message to your exceptions, save exceptions, and examine an exception occurences when they are raised.
Traceback is a technique to examine the run-time stack and identify where an exception occurred. Gnat can identify the specific source file and line where an exception occurred. To use tracebacks in Linux, you must compile your program with the -funwind-tables switch and bind with the -E switch.
[Zero-cost exceptions not covered yet--KB]
with Ada.Text_IO,Ada.Exceptions,Gnat.Current_Exception,Gnat.Traceback.Symbolic; use Ada.Text_IO,Ada.Exceptions,Gnat.Current_Exception,Gnat.Traceback.Symbolic; procedure exc is e : exception; saved_exception : Exception_Occurrence; procedure CrashMe is begin Raise_Exception( e'identity, "call exec development team" ); end CrashMe; begin Put_Line( "This is an example of the Ada.Exceptions package" ); New_Line; -- Information about an exception that is not in progress Put_Line( "Exception_Name returns a unique name for an exception" ); Put_Line( "The unique name our exception is " & Exception_Name( e'identity ) ); New_Line; -- Raising an exception with a message Put_Line( "raise will raise an exception with no message" ); New_Line; Put_Line( "Raise_Exception will raise an exception with a message" ); Put_Line( "Raising " & Exception_Name( e'identity ) & " with the message 'call exc development team'" ); Put_Line( "in the subprogram 'CrashMe'." ); New_Line; CrashMe; exception when occurrence: others => -- Information about an exception that is is in progress Put_Line( "-------------------------------------------------------" ); Put_Line( "An exception has been raised! Now in exception handler" ); Put_Line( "The name of the exception is " & Exception_Name( occurrence ) ); New_Line; Put_Line( "Exception_Message returns the message for this exception" ); Put_Line( "The message for this exception is '" & Exception_Message( occurrence ) & "'" ); New_Line; Put_Line( "Exception_Information provides the name, message and any traceback information:" ); Put_Line( Exception_Information( occurrence ) ); New_Line; Put_Line( "The Gnat.Current_Exception package contains short-hand" ); Put_Line( "versions of Exception_Name, Exception_Message, Exception_Information." ); Put_Line( "These functions assume you're referring to the current exception" ); Put_Line( "Gnat.Current_Exception.Exception_Name is " & Exception_Name ); Put_Line( "Gnat.Current_Exception.Exception_Message is '" & Exception_Message & "'"); New_Line; Put_Line( "The Gnat.Traceback.Symbolic package returns the contents of the" ); Put_Line( "runtime stack. That is, it shows which subprograms were being" ); Put_Line( "executed when the exception occurred." ); Put_Line( "The symbolic traceback is" ); Put_Line( Symbolic_Traceback( occurrence ) ); New_Line; Put_Line( "Ada.Exceptions can also save and re-raise in-progress exceptions" ); New_Line; Put_Line( "Save_Occurence can save the in-progress exception" ); Save_Occurrence( saved_exception, occurrence ); Put_Line( "Exception now saved." ); New_Line; Put_Line( "Reraise_Occurrence will raise an in-progress exception" ); Put_Line( "Reraising the one we just saved..." ); Reraise_Occurrence( saved_exception ); --Allocate/DeallocateMachineState not covered--for zero-cost exceptions end exc;
This is an example of the Ada.Exceptions package Exception_Name returns a unique name for an exception The unique name our exception is EXC.E raise will raise an exception with no message Raise_Exception will raise an exception with a message Raising EXC.E with the message 'call exc development team' in the subprogram 'CrashMe'. ------------------------------------------------------- An exception has been raised! Now in exception handler The name of the exception is EXC.E Exception_Message returns the message for this exception The message for this exception is 'call exec development team' Exception_Information provides the name, message and any traceback information: Exception name: EXC.E Message: call exec development team The Gnat.Current_Exception package contains short-hand versions of Exception_Name, Exception_Message, Exception_Information. These functions assume you're referring to the current exception Gnat.Current_Exception.Exception_Name is E Gnat.Current_Exception.Exception_Message is 'call exec development team' The Gnat.Traceback.Symbolic package returns the contents of the runtime stack. That is, it shows which subprograms were being executed when the exception occurred. The symbolic traceback is 0x8049cb3 in exc at exc.adb:10 Ada.Exceptions can also save and re-raise in-progress exceptions Save_Occurence can save the in-progress exception Exception now saved. Reraise_Occurrence will raise an in-progress exception Reraising the one we just saved... raised EXC.E : call exec development team Call stack traceback locations: 0x80497eb
Because the reraised exception propogated all the way to the main program and caused it to fail, the final line was actually written to Standard_Error.
<--Last Chapter | Table of Contents | Next Chapter--> |