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: <number> 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 ggr...@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 ggr...@2sprint.net.