Michael Coughlan

Home > Other > Michael Coughlan > Page 38


  Problem Solution

  Add an explicit scope delimiter to the IF statement:

  IF Rem = 0

  DISPLAY "Even number of people"

  ELSE

  DISPLAY "Odd number of people"

  END-IF

  STOP RUN.

  301

  Chapter 12 ■ advanCed data deClaration

  Program 4

  Problem Cause

  The problem with this program is that the programmer tries to modify the PERFORM..VARYING counter variable Counter1

  in order to force the loop to terminate prematurely. Unfortunately, the programmer has not consulted the flowchart shown in Figure 12-18. That flowchart shows that as control exits, the paragraph Counter1 is incremented. Because Counter1 has been given a value of 99 in the paragraph, the increment brings it to 100. But Counter1 is described as PIC 99 and only has room for two digits. This means the 1 is truncated, leaving Counter1 with a value of 00. Because the terminating condition Counter1 > 10 has not been satisfied, the loop will not terminate.

  Figure 12-18. Flowchart showing how the single-counter PERFORM..VARYING works

  Problem Solution

  A simple solution is to change the description of Counter1 to PIC 999. A more complex solution would require you rewrite the program so that it does not require the counting variable to be changed in the loop. When you use a construct such as the PERFORM..VARYING, you make a contract with the reader that construct will operate in the normal way and that the counting variable will take the values specified in the PERFORM. If you break that contract, you create uncertainty in the mind of the reader not only for this loop but also for all the loops in the program. Now the reader has to scrutinize each one to make sure they work as expected.

  References

  1. Vorontsov M. Using double/long vs. BigDecimal for monetary calculations. 2013 Feb. http://java-performance.

  info/bigdecimal-vs-double-in-financial-calculations/

  2. IBM. Decimal arithmetic FAQ. 2008. http://speleotrove.com/decimal/decifaq.html

  302

  Chapter 13

  Searching Tabular Data

  In previous chapters, you saw how to create and use tabular data. This chapter returns to the issue of processing tabular data to examine the operation of the SEARCH and SEARCH ALL verbs. SEARCH is used for linear searches, and SEARCH ALL is used for binary searches.

  The chapter begins by noting that when you use SEARCH or SEARCH ALL, the table they are searching must have an associated table index. You learn the metalanguage for the INDEXED BY clause used to specify the table index and explore the nature of the index data item. Because index data items can’t be manipulated by ordinary COBOL verbs, the chapter introduces the versions of the SET verb that are used to assign, increment, and decrement table index values.

  With the background material covered, you see how the SEARCH verb operates on single-dimension tables

  and work through an example. The chapter highlights the limitations of the SEARCH with regard to searching multidimensional tables and suggests, and demonstrates, a solution.

  The SEARCH verb searches a table serially. To search a table using a binary search, you must use SEARCH ALL. You learn that the SEARCH ALL can only work correctly if the table is ordered, and the chapter discusses the extension to the OCCURS clause that allows you to identify the data item on which the table is ordered. You see how a binary search works along with an example of the operation of SEARCH ALL.

  Finally, the chapter introduces the notion of variable-length tables. Although variable-length tables are not truly dynamic, they are still useful, because the variable size limitations are obeyed by COBOL verbs such as the SEARCH and SEARCH ALL. You see this with an example program.

  SEARCHING Tabular Data

  The task of searching a table to determine whether it contains a particular value is a common operation. The method used to search a table depends heavily on the way the values are organized in the table. If the values are not ordered, then the only strategy available is a linear search. A linear search starts at the first element and then examines each succeeding element until the item is found or until the end of the table is reached (item not found). If the values are ordered, then you have the option of using either a linear search or a binary search. A binary search works by dividing the table in half and determining whether the item sought is in the top half of the table or the bottom half. This process continues until the item is found or it is determined that the item is not in the table.

  COBOL has special verbs that let you search tables using either strategy. The SEARCH verb is used for linear searches, and the SEARCH ALL verb is used for binary searches.

  Searching Using SEARCH and SEARCH ALL

  One advantage of using SEARCH or SEARCH ALL rather than a handcrafted search is that because these are specialized instructions, their operation can be optimized. Part of that optimization involves creating a special subscript to be used when searching the table. You create this special subscript using an extension to the OCCURS clause called the INDEXED BY clause.

  303

  Chapter 13 ■ SearChing tabular Data

  INDEXED BY Clause

  Before you can use SEARCH or SEARCH ALL to search a table, you must define the table as having an index item associated with it. Using an index makes the searching more efficient. Because the index is linked to a particular table, the compiler—taking into account the size of the table—can choose the most efficient representation possible for the index. This speeds up the search.

  The index is specified by the IndexName given in an INDEXED BY clause attached to the OCCURS clause. The

  extended OCCURS clause metalanguage is shown in Figure 13-1.

  Figure 13-1. OCCURS metalanguage, including the INDEXED BY clause

  The following are some things to consider about Figure 13-1:

  • The index defined in a table declaration is associated with that table and is the subscript that

  SEARCH or SEARCH ALL uses to access the table.

  • The only entry that needs to be made for an IndexName is to use it in an INDEXED BY phrase. It

  does not require a PICTURE clause, because the compiler handles its declaration automatically.

  • Because of its special binary representation, the table index cannot be displayed, and its

  value cannot be manipulated using ordinary COBOL verbs such as MOVE, ADD, and SUBTRACT.

  Only four COBOL verbs can change the value of a table index: SEARCH, SEARCH ALL,

  PERFORM..VARYING, and SET.

  • Index names must be unique.

  • An index is only valid for the table to which it is bound. An index bound to one table cannot

  be used with another table.

  Using SET to Manipulate the Table Index

  A table index is a special data item. It has no PICTURE clause, it is associated with a particular table, and the compiler defines the index using the most computationally efficient representation possible. Because of its special binary representation, the table index cannot be displayed and can only be assigned a value, or have its value assigned, by the SET verb. Similarly, the SET verb must be used to increment or decrement the value of an index item.

  The metalanguage for the formats of the SET verb that are used to manipulate the value of an index item are given in Figure 13-2.

  Figure 13-2. Metalanguage for SET formats used to manipulate index values

  304

  Chapter 13 ■ SearChing tabular Data

  The SEARCH Verb

  When the values in a table are not ordered, the only searching strategy available is a linear search. You start at the first element and then search through the table serially, element by element, until either you find the item you seek or you reach the end of the table. You use the SEARCH verb when you want to search a table serially. The metalanguage for the SEARCH verb is given in Figure 13-3.

  Figure 13-3. Metalanguage for the SEARCH verb
<
br />   Note the following about Figure 13-3:

  • Before you can use SEARCH to search TableName, you must define a table index for the table in

  an INDEXED BY clause attached to the OCCURS clause that defines the table. The index specified

  in the INDEXED BY clause of TableName is the controlling index (subscript) of SEARCH. The

  controlling index controls the submission of the elements, or element items, for examination

  by the WHEN phrase of SEARCH. A SEARCH can have only one controlling index.

  • TableName must identify a data item in the table hierarchy with both OCCURS and INDEXED BY

  clauses.

  • SEARCH searches a table serially, starting at the element pointed to by the table index. This

  means the table index is under your control.

  • Because the table index is under your control, before SEARCH executes you must SET the table

  index to point to one of the elements in the table (usually the first element).

  • When SEARCH executes, the table index cannot have a value less than one or greater than the

  size of the table, or SEARCH will immediately terminate.

  • The VARYING phrase is used for a number of purposes:

  •

  When more than one index is attached to the table (note the ellipsis after IndexName in

  Figure 13-1), IndexItem identifies the IndexName that SEARCH uses as the table index.

  •

  When IndexItem is an index attached to another table or is a data item defined as USAGE

  IS INDEX, SEARCH increments the IndexItem at the same time and by the same amount as

  the table index.

  •

  When a non-index data item is used, SEARCH increments the data item by one each time it

  increments the table index.

  • If AT END is specified and the index is incremented beyond the highest legal occurrence for the

  table (that is, the item has not been found), then the statement following AT END is executed

  and SEARCH terminates.

  • The WHEN conditions attached to SEARCH are evaluated in turn. As soon as one is true, the

  statements following the WHEN phrase are executed, SEARCH ends, and the table index remains

  set at the value it had when the condition was satisfied.

  305

  Chapter 13 ■ SearChing tabular Data

  SEARCH Examples

  This section contains a number of examples that show how SEARCH is used. The section starts with a simple example by way of introduction and then ratchets up the complexity.

  Letter Position Example

  The example shown in Listing 13-1 uses SEARCH to discover the alphabet position of a letter entered by the user.

  Listing 13-1. Finding the Position of a Letter in the Alphabet

  IDENTIFICATION DIVISION.

  PROGRAM-ID. Listing13-1.

  AUTHOR. Michael Coughlan.

  DATA DIVISION.

  WORKING-STORAGE SECTION.

  01 LetterTable.

  02 TableValues.

  03 FILLER PIC X(13)

  VALUE "ABCDEFGHIJKLM".

  03 FILLER PIC X(13)

  VALUE "NOPQRSTUVWXYZ".

  02 FILLER REDEFINES TableValues.

  03 Letter PIC X OCCURS 26 TIMES

  INDEXED BY LetterIdx.

  01 IdxValue PIC 99 VALUE ZEROS.

  01 LetterIn PIC X.

  88 ValidLetter VALUE "A" THRU "Z".

  PROCEDURE DIVISION.

  FindAlphabetLetterPosition.

  PERFORM WITH TEST AFTER UNTIL ValidLetter

  DISPLAY "Enter an uppercase letter please - " WITH NO ADVANCING

  ACCEPT LetterIn

  END-PERFORM

  SET LetterIdx TO 1

  SEARCH Letter

  WHEN Letter(LetterIdx) = LetterIn

  SET IdxValue TO LetterIdx

  DISPLAY LetterIn, " is in position ", IdxValue

  END-SEARCH

  STOP RUN.

  I use a loop to get a valid uppercase letter from the user. Because the loop will exit only when a valid letter has been entered, the AT END clause is not used in SEARCH because the letter is always found in the table.

  306

  Chapter 13 ■ SearChing tabular Data

  LetterIdx is the table index. It is automatically incremented by SEARCH. Note how it is associated with the table by means of the INDEXED BY clause.

  Before SEARCH executes, the SET verb is used to set the table index (LetterIdx) to the position in the table where I want SEARCH to start.

  Finally, because LetterIdx is a special binary index item, you can’t display its value directly. So IdxValue, a numeric data item whose value can be displayed, is set to value of LetterIdx, and then IdxValue is displayed.

  American States Example

  The program in Listing 13-2 uses SEARCH to interrogate a table of American states, their ISO two-letter codes, and their capitals. The user is asked to choose the state code, state name, or state capital as their search term. Whichever is chosen, the program displays the other two. For instance, if the user chooses to search on the state code, then the program displays the state name and the state capital. If the state name is chosen, then the program displays the state code and state capital.

  Listing 13-2. Given One of StateCode, StateName, or StateCapital, Display the Other Two

  IDENTIFICATION DIVISION.

  PROGRAM-ID. Listing13-2.

  AUTHOR. Michael Coughlan.

  DATA DIVISION.

  WORKING-STORAGE SECTION.

  01 StatesTable.

  02 StateValues.

  03 FILLER PIC X(60)

  VALUE "ALAlabama Montgomery AKAlaska Juneau".

  03 FILLER PIC X(60)

  VALUE "AZArizona Phoenix ARArkansas Little Rock".

  03 FILLER PIC X(60)

  VALUE "CACalifornia Sacramento COColorado Denver".

  03 FILLER PIC X(60)

  VALUE "CTConnecticut Hartford DEDelaware Dover".

  03 FILLER PIC X(60)

  VALUE "FLFlorida Tallahassee GAGeorgia Atlanta".

  03 FILLER PIC X(60)

  VALUE "HIHawaii Honolulu IDIdaho Boise".

  03 FILLER PIC X(60)

  VALUE "ILIllinois Springfield INIndiana Indianapolis".

  03 FILLER PIC X(60)

  VALUE "IAIowa Des Moines KSKansas Topeka".

  03 FILLER PIC X(60)

  VALUE "KYKentucky Frankfort LALouisiana Baton Rouge".

  03 FILLER PIC X(60)

  VALUE "MEMaine Augusta MDMaryland Annapolis".

  03 FILLER PIC X(60)

  VALUE "MAMassachusetts Boston MIMichigan Lansing".

  03 FILLER PIC X(60)

  VALUE "MNMinnesota Saint Paul MSMississippi Jackson".

  03 FILLER PIC X(60)

  VALUE "MOMissouri Jefferson CityMTMontana Helena".

  307

  Chapter 13 ■ SearChing tabular Data

  03 FILLER PIC X(60)

  VALUE "NENebraska Lincoln NVNevada Carson City".

  03 FILLER PIC X(60)

  VALUE "NHNew Hampshire Concord NJNew Jersey Trenton".

  03 FILLER PIC X(60)

  VALUE "NMNew Mexico Santa Fe NYNew York Albany".

  03 FILLER PIC X(60)

  VALUE "NCNorth CarolinaRaleigh NDNorth Dakota Bismarck".

  03 FILLER PIC X(60)

  VALUE "OHOhio Columbus OKOklahoma Oklahoma City".

  03 FILLER PIC X(60)

  VALUE "OROregon Salem PAPennsylvania Harrisburg".

  03 FILLER PIC X(60)

  VALUE "RIRhode Island Providence SCSouth CarolinaColumbia".

  03 FILLER PIC X(60)

  VALUE "SDSouth Dakota Pierre TNTennessee Nashville".

  03 FILLER PIC X(60)

  VALUE "TXTexas Austin UTUtah Salt Lake City".

  03 FILLER PIC X(60)

  VALUE "VTVermont Montpelier VAVirginia Richmond".

  03 FILLER PIC X(60)<
br />
  VALUE "WAWashington Olympia WVWest Virginia Charleston".

  03 FILLER PIC X(60)

  VALUE "WIWisconsin Madison WYWyoming Cheyenne".

  02 FILLER REDEFINES StateValues.

  03 State OCCURS 50 TIMES

  INDEXED BY StateIdx.

  04 StateCode PIC XX.

  04 StateName PIC X(14).

  04 StateCapital PIC X(14).

  01 StateNameIn PIC X(14).

  01 StateCapitalIn PIC X(14).

  01 StateCodeIn PIC XX.

  01 SearchChoice PIC 9 VALUE ZERO.

  88 ValidSearchChoice VALUES 1, 2, 3, 4.

  88 EndOfInput VALUE 4.

  PROCEDURE DIVISION.

  Begin.

  PERFORM WITH TEST AFTER UNTIL EndOfInput

  PERFORM WITH TEST AFTER UNTIL ValidSearchChoice

  DISPLAY SPACES

  DISPLAY "Search by StateCode (1), StateName (2), StateCapital (3), STOP (4) - "

  WITH NO ADVANCING

  ACCEPT SearchChoice

  END-PERFORM

  308

  Chapter 13 ■ SearChing tabular Data

  SET StateIdx TO 1

  EVALUATE SearchChoice

  WHEN 1 PERFORM GetNameAndCapital

  WHEN 2 PERFORM GetCodeAndCapital

  WHEN 3 PERFORM GetCodeAndName

  END-EVALUATE

  END-PERFORM

  STOP RUN.

  GetNameAndCapital.

  DISPLAY "Enter the two letter State Code - " WITH NO ADVANCING

  ACCEPT StateCodeIn

  MOVE FUNCTION UPPER-CASE(StateCodeIn) TO StateCodeIn

  SEARCH State

  AT END DISPLAY "State code " StateCodeIn " does not exist"

  WHEN StateCode(StateIdx) = StateCodeIn

  DISPLAY "State Name = " StateName(StateIdx)

  DISPLAY "State Capital = " StateCapital(StateIdx)

  END-SEARCH.

  GetCodeAndCapital.

 

‹ Prev