[comp.lang.pascal] Number-string conversions

markh@csd4.milw.wisc.edu (Mark William Hopkins) (05/17/88)

     While the issue is "on the table", I feel it appropriate to give a few 
procedures to show how the conversions take place when Pascal reads & writes
in a text file.

READING INTEGERS FROM TEXT:
     procedure ReadInt(var T : text; var I : integer);
     var
	Sign : char;
     begin
	(*** SKIP SPACES ***)
	while T^ = ' ' do get(T);

        (*** GET THE SIGN ***)
	if T^ in ['+','-'] then begin
	   read(T, Sign)
        end
	else Sign := '+';

	(*** CONVERT THE STRING TO AN INTEGER ***)
	I := 0;
	while T^ in ['0'..'9'] do begin
	   I := 10*I + ord(T^) - ord('0');
	   get(T)
        end;

	(*** ADJUST FOR THE SIGN ***)
	if Sign = '-' then I := -I
     end;

READING REAL NUMBERS FROM TEXT:
(The syntax allowed by this procedure is slightly more liberal 
 than that which standard Pascal allows for.)

     procedure ReadReal(var T : text; var R : real);
     var 
	Exponent : integer;
	Power    : real;
     begin
	(*** CONVERT THE INTEGER PART ***)
	ReadInt(T, R);

	(*** CONVERT THE DECIMAL PART ***)
	if T^ = '.' then begin
	   get(T);
	   Power := 1; 
	   while T^ in ['0'..'9'] do begin
	      Power := Power / 10;
	      R := R + ( ord(T^) - ord('0') ) * Power;
	      get(T)
           end
        end;

	(*** CONVERT THE EXPONENT PART ***)
	if T^ in ['e','E'] then begin
	   get(T);
	   ReadInt(T, Exponent);
	   while Exponent > 0 do begin
	      Exponent := Exponent - 1; R := R * 10
           end;
	   while Exponent < 0 do begin
	      Exponent := Exponent + 1; R := R / 10
           end
        end
     end;	

FORMATTING INTEGERS INTO TEXT:
     procedure WriteInt(T : text; I : integer; FieldWidth : integer);
     var
	Sign : char;
	Size, Exponent : integer;
     begin
	(*** DETERMINE THE SIGN ***)
	if I < 0 then begin
	   Sign := '-'; I := -I
        end
	else if I > 0 then Sign := '+'
	else Sign := '0';
        
	(*** DETERMINE THE SIZE OF THE INTEGER STRING ***)
	Exponent := 1; Size := 0;
	while (Exponent < I) do begin
	   Exponent := 10 * Exponent; Size := Size + 1
        end;

        (*** PAD THE INTEGER TO THE LEFT, IF NECESSARY ***)
	if FieldWidth > Size then begin
	   while FieldWidth > Size + 1 do begin
	      FieldWidth := FieldWidth - 1; write(T, ' ')
           end;
	   if Sign = '+' then write(T, ' ')
        end;

	(*** CONVERT THE NUMBER TO A STRING ***)
	if Sign = '+' then write(T, ' ')
	else if Sign = '-' then write(T, '-')
	else if Sign = '0' then write(T, '0'); 
	else while Size > 0 do begin
	   Size := Size - 1;
	   Exponent := Exponent / 10;
	   write(T, chr(I mod Exponent + ord('0')) );
	   I := I div Exponent
        end
     end;

FORMATTING REALS TO TEXT:
(F1, F2 are the two field widths used for formatting real numbers and
 rounding them to the desired number of decimal places.)

     procedure WriteReal(var T : text; R : real; FW1, FW2 : integer);
     var
	Mantissa : integer;
        Decimal : real;
     begin
	Mantissa := trunc(R); Decimal := R - Mantissa;

	(*** The field width FW1 includes the decimal part and decimal ***)
	(*** point in it.  Therefore the integer part is written out   ***)
	(*** with a field width of FW1 - FW2 - 1.                      ***)

	WriteInt(T, Mantissa, FW1 - FW2 - 1);
	if FW2 > 0 then begin
	   write(T, '.');
	   while FW2 > 1 do begin
	      FW2 := FW2 - 1;
	      Decimal := Decimal * 10;
	      write(T, chr( trunc(Decimal) + ord('0') ) );
	      Decimal := Decimal - trunc(Decimal)
           end;

	   (*** ROUND THE LAST DECIMAL DIGIT ***)
           Decimal := Decimal * 10;
	   write(T, chr( round(Decimal) + ord('0') ) )
        end
     end

firth@sei.cmu.edu (Robert Firth) (05/17/88)

In article <5817@uwmcsd1.UUCP> markh@csd4.milw.wisc.edu (Mark William Hopkins) writes:

>     While the issue is "on the table", I feel it appropriate to give a few 
>procedures to show how the conversions take place when Pascal reads & writes
>in a text file.

Some comments on these procedures are given thus: [! ... ]

READING INTEGERS FROM TEXT:

     procedure ReadInt(var T : text; var I : integer);
     var
	Sign : char;
     begin
	(*** SKIP SPACES ***)
	while T^ = ' ' do get(T);	[! may run off the end of the file]

        (*** GET THE SIGN ***)
	if T^ in ['+','-'] then begin
	   read(T, Sign)
        end
	else Sign := '+';

	(*** CONVERT THE STRING TO AN INTEGER ***)
	I := 0;
	while T^ in ['0'..'9'] do begin
	   I := 10*I + ord(T^) - ord('0');	[! may cause false overflow
						   on '+' if number large]
	   get(T)
        end;

	(*** ADJUST FOR THE SIGN ***)
	if Sign = '-' then I := -I		[! and of course fails on the
						   most negative integer]
     end;

READING REAL NUMBERS FROM TEXT:
(The syntax allowed by this procedure is slightly more liberal 
 than that which standard Pascal allows for.)

     procedure ReadReal(var T : text; var R : real);
     var 
	Exponent : integer;
	Power    : real;
     begin
	(*** CONVERT THE INTEGER PART ***)
	ReadInt(T, R);			[! will overflow on eg 10000000000.0]

	(*** CONVERT THE DECIMAL PART ***)
	if T^ = '.' then begin
	   get(T);
	   Power := 1; 
	   while T^ in ['0'..'9'] do begin
	      Power := Power / 10;	[! cumulative loss of precision since
					   binary 0.1 is approximate]
	      R := R + ( ord(T^) - ord('0') ) * Power;
	      get(T)
           end
        end;

	(*** CONVERT THE EXPONENT PART ***)
	if T^ in ['e','E'] then begin
	   get(T);
	   ReadInt(T, Exponent);
	   while Exponent  0 do begin
	      Exponent := Exponent - 1; R := R * 10
           end;
	   while Exponent < 0 do begin
	      Exponent := Exponent + 1; R := R / 10	[! further loss of
							   precision]
           end
        end
     end;	

FORMATTING INTEGERS INTO TEXT:
     procedure WriteInt(T : text; I : integer; FieldWidth : integer);
     var
	Sign : char;
	Size, Exponent : integer;
     begin
	(*** DETERMINE THE SIGN ***)
	if I < 0 then begin
	   Sign := '-'; I := -I		[! fails on most negative number]
        end
	else if I > 0 then Sign := '+'
	else Sign := '0';
        
	(*** DETERMINE THE SIZE OF THE INTEGER STRING ***)
	Exponent := 1; Size := 0;
	while (Exponent < I) do begin
	   Exponent := 10 * Exponent;	[! overflow if I near MAXINT/10 ]
           Size := Size + 1
        end;

        (*** PAD THE INTEGER TO THE LEFT, IF NECESSARY ***)
	if FieldWidth  Size then begin
	   while FieldWidth > Size + 1 do begin
	      FieldWidth := FieldWidth - 1; write(T, ' ')
           end;
	   if Sign = '+' then write(T, ' ')
        end;

	(*** CONVERT THE NUMBER TO A STRING ***)
	if Sign = '+' then write(T, ' ')
	else if Sign = '-' then write(T, '-')
	else if Sign = '0' then write(T, '0'); 
	else while Size > 0 do begin
	   Size := Size - 1;
	   Exponent := Exponent / 10;
	   write(T, chr(I mod Exponent + ord('0')) );
	   I := I div Exponent
        end
     end;

FORMATTING REALS TO TEXT:
(F1, F2 are the two field widths used for formatting real numbers and
 rounding them to the desired number of decimal places.)

     procedure WriteReal(var T : text; R : real; FW1, FW2 : integer);
     var
	Mantissa : integer;
        Decimal : real;
     begin
	Mantissa := trunc(R); 		[! overflow if R > MAXINT ]
        Decimal := R - Mantissa;

	(*** The field width FW1 includes the decimal part and decimal ***)
	(*** point in it.  Therefore the integer part is written out   ***)
	(*** with a field width of FW1 - FW2 - 1.                      ***)

	WriteInt(T, Mantissa, FW1 - FW2 - 1);
	if FW2 > 0 then begin
	   write(T, '.');
	   while FW2 > 1 do begin
	      FW2 := FW2 - 1;
	      Decimal := Decimal * 10;
	      write(T, chr( trunc(Decimal) + ord('0') ) );
	      Decimal := Decimal - trunc(Decimal)
           end;

	   (*** ROUND THE LAST DECIMAL DIGIT ***)	[! fails if rounding
							   involves more than
							   one digit ]
           Decimal := Decimal * 10;	
	   write(T, chr( round(Decimal) + ord('0') ) )
        end
     end


[ Me again, Robert Firth ]

I find it hard to express my feelings in a manner that is both clear and
polite.  The above code is evidently rubbish; unfortunately it is typical
of the stuff produced by amateur software writers - you can find examples
galore, as bad or worse, in many packages distributed by major institutes
of education.

These examples would not have survived any one of: accurate specification,
competent design review, code walkthrough, formal analysis, or thorough
testing.  I conclude that they were subjected to none of these processes.

Folks, are we surprised there is a "software crisis"?  And what can we,
as responsible individuals, do about it?

markh@csd4.milw.wisc.edu (Mark William Hopkins) (05/20/88)

In a previous article firth@bd.sei.cmu.edu.UUCP (Robert Firth) writes:

<CONCERNING SOME REASONABLY WRITTEN PROCEDURES 
 THAT HAD BEEN PREVIOUSLY PLACED ON THE NET>:

>[ Me again, Robert Firth ]

welcome back, we almost lost you there.

>
>I find it hard to express my feelings in a manner that is both clear and
>polite.  The above code is evidently rubbish; unfortunately it is typical
>of the stuff produced by amateur software writers - you can find examples
>galore, as bad or worse, in many packages distributed by major institutes
>of education.
>
>These examples would not have survived any one of: accurate specification,
>competent design review, code walkthrough, formal analysis, or thorough
>testing.  I conclude that they were subjected to none of these processes.
>
>Folks, are we surprised there is a "software crisis"?  And what can we,
>as responsible individuals, do about it?

     Never mind that these comments are innappropriate in this context, I do
feel that a suitable response is in order.  This story ... from another
newsgroup in the past ... most properly expresses my sentiments about the
points raised in the poster's article:

********************************************************************************

Subject: A Gown for the Princess: A Parable for Software Engineers

Communications of the ACM, September 1987, Volume 30, Number 9, p. 750-751
president's letter
by Paul Abrahams, acm president

Copyright 1987 by the Association for Computing Machinery, Inc.  Copying
without fee is permitted provided that the copies are not made or
distributed for direct commercial advantage and credit to the source is
given.

------------------------------------------------------------

A Gown for the Princess: A Parable for Software Engineers

Once upon a time, there lived a king who had a beautiful daughter.  The king
wished nothing more than to make her happy, and so he resolved that the
princess should have a fine new gown that would match her beauty.  He
summoned the wisest and most silled tailor in all of his kingdom to make a
gown for the princess.  "My daughter shall have the finest gown in the
land," declared the king.

"Before I can make such a gown," said the tailor, "I must know what it is
that you require."  And the tailor discoursed at length about the materials
that might be used, the cuts and patterns to be chosen, the method of
joining and seaming, the decorations, and other such matters.  He spoke of
gores and pleats, of hems and stitches, of darts and shirring, of embroidery
and lace.  The poor king knew nothing of such matters.  "I just want a
beautiful gown for my daughter!" he exclaimed.  "I shall do my best," said
the tailor."

The next week the tailor returned to the palace.  He brought a large sheaf
of documents and presented them to the king.  "These are the specifications
I propose for the gown, your Majesty.  I hope it is what you want.  It shall
be completed in a year's time.  And for my labors and the labors of my
assistants, I must humbly ask your Majesty for fifty thousand ducats."
"These tailors charge the earth and the sky," thought the king, "but there
is nothing to do but to pay it and hope for the best."  The king nodded
sadly, "It shall be as you propose," said the king, and he placed the royal
seal upon the specification.

The tailor then appointed himself as Chief Tailor and summoned a score of
apprentice tailors to assist him.  He explained to them how, together, they
would create the gown.  "Let us decompose the task into its parts: the
sleeves, the bodice, the waist, the skirt, and the adornments.  Each one of
you is to prepare a part of the gown, and my task is to specify the parts
and discern how they are to be fitted together.  But hasten not to your loom
and your table; we first must plan how each part is to be prepared and
decompose the task until the smallest detail is known.

We must verify beyond the shadow of doubt that the gown we create will meet
its specification.  To that end we must prove that all its parts will fit
together and that each part is as the larger design would have it.  Through
such verification we may know, before the first stitch is taken, that the
gown will render honor to the princess of the realm and be as the king has
ordered."

Months went by, and the Chief Tailor and his assistants filled sheets of
paper with drawings of the gown and of all its parts.  Yet the fine fabrics
purchased for the gown remained in the storehouse, and not a stitch had been
sewn.  The king began to worry that the gown would not be completed within
the year.  He summoned the Chief Tailor to the court and asked why the gown
had not yet been started.  "The execution shall follow upon the plan, as the
night upon the day," said the Chief Tailor.  "I shall not take needle and
thread to hand until the gown has been completely designed."  And so it was.

But at last the design was done, and the great enterprise began to take
shape.  Fabrics were woven, and the team of tailors went busily about their
work of cutting, sewing, and shaping.  As the different parts of the gown
were completed, the tailors brought them to the Chief Tailor for assembly.
Here was the most difficult part of the whole effort, for it seemed that,
whenever two parts were joined, a piece of fabric remained on one side or
the other.  Many times the tailors had to take back their work and resew it,
and arguments broke out among them as to who was at fault.

One day the Chief Tailor came to the king.  "Alas, your Majesty, the
allotted sum is not sufficient to complete the gown.  For the princess has
grown in girth since the measurements were made, and it is now necessary to
alter the plan.  I must ask an additional thousand ducats if it is to be
completed on time."  Sadly the king nodded.  "Go and do it, then," he said.

At last, after a year and a half, the gown was completed and brought to the
princess for a demonstration.  Alas, the poor girl was unable to put it on,
for the chief tailor, in his quest for excellence of shape, had forgotten to
provide any buttons.  Hastily the tailor modified the gown, and the princess
then showed it to the king. "Is the gown acceptable?" asked the Chief
Tailor. "It is, indeed," answered the king.  But the king was troubled at
heart, for somehow the gown did not look at all like what he had expected.

Several days later the princess was walking in the garden of the palace,
wearing her new gown.  As she reached up to pluck a grape, the top of the
gown slid down, exposing her bosom for all to view.  The king was very
distressed and angrily summoned the Chief Tailor.  "What kind of a gown have
you made for my daughter!" he exclaimed.  "Not only has it made her look
foolish, but I paid you fifty thousand ducats for it!"

"Prithee, your Majesty," said the tailor.  "The gown was made according to
the specifications that you agreed to.  Nowhere did we speak of this matter,
that the gown should remain in one place only.  Indeed, 'tis not a fault but
a feature of the gown, that your daughter's beauty should be displayed to
all the folk of the land.  But, if your Majesty desires to alter the gown, I
must humbly request another fifteen hundred ducats for the immense labor
necessary to meet your wishes."  Sadly the king nodded. "Go and do it,
then," he said.

A few years later, the Chief Tailor was turned into a frog by a disgruntled
witch whose affections he had spurned.  Hardly had the Chief Tailor been
transformed than strange stains and rips appeared in the gown.  The Backup
Tailor, who had been appointed by the Chief Tailor to maintain the gown,
examined it closely, seeking to repair it.  But the documents that described
the design were not to be found, and the Backup Tailor finally had to give
up.  The princess put the gown in the back of her closet, and there it
remains to this very day.

------------------------------------------------------------

markh@csd4.milw.wisc.edu (Mark William Hopkins) (05/21/88)

     This is a followup from the previous article and addresses more directly
the response of R. Firth several articles back concerning the nature of 
several number-to-string procedures listed previously:

<MY INTENTIONS>:
>     While the issue is "on the table", I feel it appropriate to give a few 
>procedures to show how the conversions take place when Pascal reads & writes
>in a text file.
...
<FOLLOWED BY LISTINGS FOR ReadInt, ReadReal, WriteInt and WriteReal>
...

<THE INAPPROPRIATE CRITICISM>:
>I find it hard to express my feelings in a manner that is both clear and
>polite.  The above code is evidently rubbish; unfortunately it is typical
>of the stuff produced by amateur software writers - you can find examples
>galore, as bad or worse, in many packages distributed by major institutes
>of education.
>
>These examples would not have survived any one of: accurate specification,
>competent design review, code walkthrough, formal analysis, or thorough
>testing.  I conclude that they were subjected to none of these processes.
>
>Folks, are we surprised there is a "software crisis"?  And what can we,
>as responsible individuals, do about it?

<THE REASONS FOR BEING INAPPROPRIATE>:
(1) The procedure listings are for show only, they are not meant to be run.
    This much is obvious, since Pascal ALREADY has the facilities built-in.

(2) The procedures are meant to SIMULATE Pascal ... for better or for worse
    ... flaws and all ... in order to demonstrate just how Pascal carries
    out the special built-in read procedures and to make explicit the
    limitations and flaws of these built-in procedures.


But in any case, I feel that the criticism should be more directly addressed:

So let us scrutinize the ReadInt procedure to see if it actually does simulate
Pascal's integer read:

THE LISTINGS:
                            P A S C A L :
                     program Pascal(input, output);
                     var I : integer;
                     begin
                        read(I); write(I:1)
                     end.

			   R e a d I n t :
                  program Simulate(input, output);
                  var I : integer;

		  ... (*** Procedure ReadInt inserted here ***)

		  begin
		     ReadInt(I); write(I:1)
                  end.

where the procedure listing is:

          procedure ReadInt(var T : text; var I : integer);
          var
	     Sign : char;
          begin
	     (*** SKIP SPACES ***)
	     while T^ = ' ' do get(T);	{! may run off the end of the file}
             (*** GET THE SIGN ***)
	     if T^ in ['+','-'] then begin
	        read(T, Sign)
             end
	     else Sign := '+';
	     (*** CONVERT THE STRING TO AN INTEGER ***)
	     I := 0;
	     while T^ in ['0'..'9'] do begin
	        I := 10*I + ord(T^) - ord('0');	{! may cause false overflow
						   on '+' if number large}
  	        get(T)
             end;
	    (*** ADJUST FOR THE SIGN ***)
	    if Sign = '-' then I := -I		{! and of course fails on the
						   most negative integer}
         end;

Let us look into some of the supposed flaws of the ReadInt procedure:

                                 (1)
                          O V E R F L O W S
     In all fairness, I should mention that the way a compiler handles
overflow is implementation dependent.  The ReadInt procedure was promised to 
simulate how Pascal reads integers ... for better or for worse.

Script started on Fri May 20 14:13:34 1988
                      T H E   I N P U T   F I L E :
(csd4) 1: more In
123456789012345

 H O W   S T A N D A R D   P A S C A L   M A Y   H A N D L E   O V E R F L O W :
(csd4) 2: pix Pascal.p <In 
Execution begins...
-2045911175
Execution terminated.

           H O W   R e a d I n t   H A N D L E S   O V E R F L O W :
(csd4) 3: pix ReadInt.p <In 
Execution begins...
-2045911175
Execution terminated.

                    T H E   R E L E V A N T   C O D E :
(csd4) 4: more ReadInt.p
 ...
     procedure ReadInt(var T : text; var I : integer);
...
	I := 0;
	while T^ in ['0'..'9'] do begin           <THE MISPLACED CRITICISM>:
	   I := 10*I + ord(T^) - ord('0');	{! may cause false overflow
						   on '+' if number large}
	   get(T)
        end;
...

So much for overflow ...

  				   (2)
         O V E R R E A D I N G   T H E   E N D - O F - F I L E :
     The question asked here is whether ReadInt successfully simulates
the way Pascal reads integers when there are no integers to be read ...

Script started on Fri May 20 14:17:01 1988
                      T H E   I N P U T   F I L E :
(csd4) 1: more In
<EMPTY>

        H O W   S T A N D A R D   P A S C A L   H A N D L E S   I T : 
(csd4) 2: pix Pascal.p <In 
Execution begins...

standard input: Tried to read past end of file

                H O W   R e a d I n t   H A N D L E S   I T :
(csd4) 3: pix ReadInt.p <In 
Execution begins...

standard input: Tried to read past end of file
...
	Error in "ReadInt"+2 near line 9.
...

                    T H E   R E L E V A N T   C O D E :
(csd4) 4: more ReadInt.p
...
     procedure ReadInt(var T : text; var I : integer);
...
     begin
	(*** SKIP SPACES ***)                <THE MISPLACED CRITICISM>:
9 --->	while T^ = ' ' do get(T);	{! may run off the end of the file}
...

"Pray tell, your majesty ... excuse me, I mean 'Your Majesty' ... a simulation 
so perfect that it even simulates the flaws!"

     Now a few words about the procedures themselves.  Nobody in their right
mind would actually set up and run text read procedures that simulated what
was already built-in.  If I were actually going to write procedures to do
text I/O they would have had ERROR CORRECTION facilities built in them.

jfjr@mitre-bedford.ARPA (Jerome Freedman) (05/23/88)

 The impending quarrel over number-string conversions will
be uninteresting to most of us but..
 This is a sidelight to this dispute. I don't intend to get
involved but it perked my curiosity. Can any body point me
to literature in which these problems are discussed (and solved)

                                         Jerry Freedman, Jr
                                          jfjr@mitre-bedford.arpa

Jerry Freedman, Jr       "Does Unix have
jfjr@mitre-bedford.arpa      a Buddha nature?"
(617)271-4563