Turbo Pascal for DOS Tutorial by Glenn Grotzinger Part 7 -- Records usage and Mathematics Concepts of Computers All parts copyright 1995 (c) by Glenn Grotzinger Here is a solution to part 6... {$B+} program part6; type ltrtype = array['A'..'Z'] of longint; {type dec for arrays} var ltrstorage, sums: ltrtype; { hold array and sums array } filelist, counts: text; filename: string; filenums: integer; ltrs: longint; procedure countletters(str: string; var ltrstorage, sums: ltrtype); var i: integer; {65..90} j: char; begin for i := 1 to length(str) do { for length of string } for j := 'A' to 'Z' do { for 26 letters } if upcase(str[i]) = j then begin inc(ltrstorage[j]); {var = var + 1 } inc(sums[j]); ltrs := ltrs + 1; end; end; procedure countfile(filename: string; var ltrstorage:ltrtype; var filenums: integer); var cntfile: text; chkstr: string; begin writeln('Processing ', filename); filenums := filenums + 1; assign(cntfile, filename); reset(cntfile); readln(cntfile, chkstr); while not eof(cntfile) do begin countletters(chkstr, ltrstorage, sums); readln(cntfile, chkstr); end; countletters(chkstr, ltrstorage, sums); close(cntfile); end; procedure writefdata(filename: string; var ltrstorage: ltrtype); var i: integer; j: char; begin { write headers } writeln(counts, 'Alphabetical Count Data':53); writeln(counts, 'for ':40, filename); writeln(counts); writeln(counts, 'Letter':10, 'Count':10, 'Letter':25, 'Count':10); for i := 1 to 13 do writeln(counts, chr(i+64):8, ltrstorage[chr(i+64)]:12, chr(i+77):23, ltrstorage[chr(i+77)]:12); writeln(counts); writeln(counts); for j := 'A' to 'Z' do ltrstorage[j] := 0; { zero back out storage array } end; procedure doend(filenums: integer; ltrstorage: ltrtype); var i: integer; j: char; begin writeln(counts, filenums, ' files processed.'); writeln(counts, ltrs, ' letters processed.'); writeln(counts); writeln(counts); writefdata('all files', sums); end; begin assign(filelist, 'FILES.TXT'); reset(filelist); assign(counts, 'FRNDDATA.TXT'); rewrite(counts); readln(filelist, filename); filenums := 0; while (not eof(filelist)) and (filenums < 9) do begin countfile(filename, ltrstorage, filenums); writefdata(filename, ltrstorage); readln(filelist, filename); end; countfile(filename, ltrstorage, filenums); writefdata(filename, ltrstorage); doend(filenums, ltrstorage); if not eof(filelist) then writeln(counts, 'You gave me more than 10 files to process!'); close(filelist); close(counts); end. On with the show.... Records Definition ================== You can group up different types of data using records. We MUST use the type statement pretty well to use this record type. Here is an example of the defining of a record type in the type section. type employeerecord = record number: longint; surname: string[18]; firstname: string[10]; position: string[10]; yrsworked: integer; end; As you can see, we are grouping many different types of information into one record type. Then for the var section, all we need to do is define ONE variable to be of type employeerecord and we'll have the record variable. Accessing Records in a Program ============================== You can work with sections of a record variable, or the whole record variable. The whole record variable can be accessed just by calling the record variable used. The parts of it require the use of a . followed by the name of the part as specified in the type statement. Also, the WITH command may be used to simplify typing in working with a specific record. The WITH command specifies a specific record variable to work with. An example can be seen below. program tutorial18; type {Employeerecord as above} var workrecord: employeerecord; begin { get workrecord into memory here. } writeln(workrecord.number); writeln(workrecord.surname); writeln('I''m getting sick of typing workrecord all the time!'); with workrecord do writeln(firstname); writeln(position); writeln(yrsworked); end; end. Hopefully, you can see what exactly is going on in working with records. WITH only reduces typing. It's good to use to reduce clutter if you do a lot with one type of record in a section of code. Also, keep in mind that record types can be used in an array.... var workinfo: array[1..10] of employeerecord; Each section of the record works just like ordinary variables, and are addressable like ordinary variables. Also the whole record itself can be addressable and moved around (written possibly to binary files?) to other like records....The above array can be addressed like this: 3rd record in array, surname: workinfo[3].surname Mathematics Concepts in Computers ================================= Hopefully, you got the mathematics lesson from someone, or are already familiar with conversion of number bases. If not, I will run through a quick example... Convert 10 (base 10) to base 2. A base tells us how many numbers are used in counting. Typical numerical usage is base 10 (we use the numbers 0-9 in that order -- we always start from zero in counting. To look at this problem, we look at the right and move to the left with regards to number bases. To use the example of 543 in base 10, it's 5X10^2+4X10^1+3X10^0. Remember, anything to the 0th power is 1. All number bases work this way. The exception is the changing of the multiple. We use 10 in the example above. Using that background, 10 in base 10 is 1X10^1+0x10^0. So, if we go through the process of actually converting a base from base 10.... 10 / 2 = 5 rem 0. (we keep going until the quotient is 0. Right now it is 5.) 5 / 2 = 2 rem 1. 2 / 2 = 1 rem 0. 1 / 2 = 0 rem 1. (We quit here. Then look at the remainders from down to up to get our converted base). 1010 is 10 in base 2....Now, if we want to go to base 10 from another number. Convert 4A (base 16 to base 10). Here, since we want to go to base 10, all we need to do is extend out the base into something we can understand... 4 X 16 + A(10) X 1 = 64 + 10 = 74 (base 10) What does all of this have to do with computers in programming. Let's analyze a few things... If you've seen $ and # and what do they mean? --------------------------------------------- $ is a typical designator in computers that a number is in base 16. # is a typical designator in computers that a number is in base 10. You probably have seen it by now in the ASCII table studies we have done. For example, Z is ASCII character $5A and #90. These are both one in the same. As we see below: 5X16^1+A(10)X16^0 = 80 + 10 = 90 (base 10). 9x10^1+0x10^0 = 5x16^1+10(A)x16^0 (base 16). {90/16 = 5 rem 10} How does my computer store data? ================================ Why do we bother to mess with the different number systems in computing? base 10 is human-understandable, so we use it sometimes. Base 2 is obvious, since this is how the computer talks. (hence BI-nary) All computer storage is actually a series of 1's and 0's or ON's and OFF's. (2 possible combinations, hence base 2). For example, lets convert #65 to base 2 and see how our computers store an A. Let's start from the highest we know we can on the power list for 2's. There are 256 ASCII characters because it was decided sometime in the computer stone age that there would be a total of 8 bits, the elementary unit of storage in a computer, per byte, or next major unit that you all should be familar with in using DOS/ Windows/whatever. If we analyze that using a good permutation scheme.. 2 possible orientations, 8 positions...2^8 or 256 total combinations. So, we will start from 7, since there is no byte #256. 128 goes into 65 0 times. 64 goes into 65 one time with 1 left. 32 goes into 1 0 times. 16 goes into 1 0 times. 8 goes into 1 0 times. 4 goes into 1 0 times. 2 goes into 1 0 times. 1 goes into 1 one time. (stepping down powers of 2.). So typically in expressing a list of bits for a byte, we use 0's for the filler for all 8 spaces, since we NEED to work for 8 bits with a respective byte. So an ASCII related system (there are others) would represent #65 as 0 1 0 0 0 0 0 1. 8 bits, all 0 or 1. If your computer deals with an A, it actually deals with the bit series 01000001. In using a computer, we don't need to know about bits, since each completely meaningful unit to most of us comprises 8 bits. We don't need to normally think of 01000001, the way the computer does it. But for some things in programming, we do, though. Base 16 is also used a lot. Reason? It's a real handy way to define a byte. Let's look at the A. According to the ASCII table, A is $41. 16 = 2^4 so we can see it's a lot handier way to tag around the implied bits of a byte with this... If we look at the bit sequence, a high end of 4 bits would have to be multiplied by 16. So if we look at the meaning of 0100 and 0001, we will see why we use base 16... 0100 is 4. 0001 is 1. Concenate them together, we get 41...Neat, eh? We don't really have all that much concern for base 16 in this tutorial, because in pascal, base 10 will work as well. we do need to be concerned about base 2, though, because the computer uses it. Reasons for knowing what this stuff is... ========================================= We have reasons that we need to know how to convert between the number bases, and be familar with what a bit is...You may be familiar with what is called the high and low orders of a byte. To use the example of the A bit series we converted earlier: 0 1 0 0 0 0 0 1 high order low order There are pascal commands which use the bits for things. Also, some fixed file formats use these (such as compression -- that's actually whats going on -- it works at bit level to compress the number of bytes used) and if you wish to if you ever develop something....) One must have an idea of where the bits are coming from, hence all the stuff I was going through before. If you read through your TP programmer's reference and see it talking about orders of bytes and what goes on with those particular commands, now, you should have the background to know about it and predict what would happen on those commands. First good commands to know about for working with bits ======================================================= We always want to go for the most efficient code available. If we ever need to work with multiplying or dividing powers of 2, we can do it much speedier and easier by having the computer do bit shifts instead of doing an actual multiply or divide command when we are dealing with small numbers. Shifting information around is much easier for the CPU than actually doing the computation. Let us demonstrate. 00000010 (base 2) = 2 (base 10) 00000010 (shift 1 byte to the left) => 00000100 or 4 (base 10) 00000010 (shift 1 byte to the right) => 00000001 or 1 (base 10) Going one way or the other in shifting bytes have the effect of multiplying or dividing by 2^(# of bytes we move). Play with these commands and you will see. It's a bit shift that it does, and is MUCH faster than an actual divide when it comes to any power of 2. Examples: writeln(2 shl 1); {or 2 X 2^1} writeln(2 shr 1); {or 2 / 2^1} Those two commands work this way: command <# of bits to shift> # of bytes to shift turns out to be the power of 2 we do the work on... HI(byte) pulls the high order of the expression. LO(byte) pulls the low order of the expression. swap(byte) swaps the orders. These are all functions. Other Math Functions offered by Pascal ====================================== Abs(X) Takes absolute value of X. Arctan(X) Takes arctangent of X. Cos(X) Takes cosine of X. Exp(X) Takes exponential (base e) of argument. Frac(X) Returns fraction of X. Int(X) Returns integer part of X. Ln(x) Takes base e logarithm of X. Pi Returns value of pi. Round(X) Rounds X(real) to an integer. sin(X) Takes sine of X. sqr(x) Takes square of X. sqrt(x) Takes square root of X. trunc(x) Truncates X w/o rounding. It is a good idea to learn basic trigonometry and analytical geometry in programming. For example, I know from my studies that Tan(x) would be 1/Arctan(x) or sin(X) / cos(X). This stuff is good to know. The reasons? Graphics. All one needs to draw anything, really, is a good spot placement procedure and knowledge of trigonometry, and analytical geometry. Just know and define a resolution and then start drawing knowing your knowledge. As a test, to help out....How would one draw a circle given a central point and radius? (Gotoxy in the CRT or WinCRT unit will be of use. It will place the cursor at a specified position so you can write something.). If anyone wants a text-based solution on this one if they can't figure it out, e-mail ggrotz@2sprint.net. I will place one in the next part. Other stuff that may prove useful ================================= In your programming experience, you may have wondered if there is a way to get a string to an integer, or an integer to a string to do things with it? Well, there is. VAL and STR. Val is used like this: Val(string, integer, errorinteger); string is the string you want to try and convert to an integer. integer is the integer that holds the successful conversion. errorinteger is <> 0 when there is an error in conversion (always check this before you move on after using a VAL!!! Str is used like this: string := str(integer); string is the string you want to hold the conversion in... integer is the integer that we want to convert... Another good command to know is POS: integer := pos(substr, str); It returns 0, if substr isn't there, but it returns a positive value corresponding to the start of the substring in the string, if it's there. For example, if we want to find the first use of the word AT in a string... int := pos('AT', 'THAT'); int will be 3. Conclusion ========== I know all of this mathematics, and talk of bits is probably confusing. If you don't understand it right now, don't worry about it and go back at leisure and study it. It is the basic extent of mathematics behind the actual operation of a computer and what we all as programmers need to keep in the back of our minds for some things. You should know what a bit is, an order of a byte is, and that there are 8 bits in a byte. These things should help out in some matters. You should know the why parts of these things in some cases...You should especially, though, understand the parts about the commands SHR, SHL, HI, LO, and SWAP, and the concepts of orders based on the storage of a byte, as, though we will not see these in this part, we will undoubtedly see them some- time before this tutorial is over, more than likely, even we may not see them. But you may need to work at bit level with bytes sometime, so this information is present here now for both the novices and the experts that may see this. Also, converting the number bases is a needed thing. Practice Programming Problem #7 =============================== The concept of a record is relatively straight forward. So I will not try to come up with a problem for basic usage of records. But the concept of writing code to do some of the number conversions is not. These functions can be very useful for later use in your programming (save them after you write them!). Write a function for your code library that will perform a base 10 to base X number conversion (X being a variable we can define in the function header to be an integer.) on an integer. Also write a function that will perform a base x to a base 10 conversion. Inbed these two functions in a program that will take a number from the keyboard (you can use whatever prompt you deem to be the least confusing as possible) and a base to convert the number to. Put out a prompt as to the answer of what the new base number of the input is, as well as a restatement of the original number inputted using a reverse conversion of base (Show us that both of the functions work and are correct. If the 2nd computed statement DOES not equal what is put in, there is an error.), not a direct reprint of the input variable. To prove we are not writing out the original input number that we placed in the keyboard, place a 0 in the keyboard input variable after you perform the function to convert it to the user's desired base. Sample Output ------------- Enter a number: 10 What base do you want to convert it to? 5 10 (base 10) is 20 (base 5). To check: 20 (base 5) is 10 (base 10). Notes: 1) You will have to build the converted number base as a string, because any base beyond 10 requires the use of the alphabet for parts of the number. 2) The best way I see to handle the "What do we use for the number in the result?" question is to define a constant string in the function to be something like '0123456789ABC...', and address a proper part of the constant string when we build the converted number for conversion. 3) Remember we count from x^0 units on the right!!!!! 4) You will need to probably make the high end limit to be base 36. 5) Hint: the base x to base 10 function will need to input a string for the input number and output a longint, while the base 10 to base x function will need to input a longint and output a string. 6) A side note for usage. You can link these two to get from any base to any base using base 10 as the intermediary. Next Time ========= We will cover the DOS file function commands out of TP. Hold on to your newsreaders because part 8 (right now) is 531 lines, and I'm not through yet. This will be one of our special topics. If you not familiar with the following concepts in DOS, look up in your DOS manual and try and pick it up before next time: Read-only file, hidden file, system file, volume label, command-line parameter, MD, RD, delete (or erase), the use of * and ? as wildcards. As always, any comments, questions, gripes, etc, send them to ggrotz@2sprint.net.