home *** CD-ROM | disk | FTP | other *** search
- ----TOADADD.DOC----
- TOADADD.PAS
-
- Turbo Pascal Inline routines for MS-DOS systems.
- First release permits you to add numeric strings to numeric strings,
- or integers to numeric strings.
-
- Sounds simple, but this gives you a handle on manipulating literally
- infinitely large numbers. (When the number depicts more than the
- number of objects in the universe, that's a pretty good definition
- of infinite, ne?)
-
- Code could be rewritten to permit use with Z80 systems, but I'll leave
- that as an exercise to the student. (Don't you just HATE that?)
-
- More to follow ... subtraction, multiplication, division, etc.
- (Keep your eyes peeled for TOADMATH.PAS.) (Unless some other Netlandian
- beats me to it.)
-
- Assembler ideas obtained from Chapter 11, "Assembler for the IBM PC and
- PC-XT", by Peter Abel ((C) 1984 Reston Publishing Company, Inc.)
- for the usual ripoff price.
-
- Works just fine on an 80286 PC clone running PC-DOS 3.1 and Turbo 3.0
- .. should be fine on any MS-DOS system and any Turbo version.
-
- Released to the public domain. (Yep, it's my code.)
-
- David Kirschbaum
- Toad Hall
- ABN.ISCAMS@USC-ISID.ARPA
-
- ----TOADADD.PAS----
- program TOADADD.PAS;
-
- {David Kirschbaum
- Toad Hall
- ABN.ISCAMS@USC-ISID.ARPA
- 7573 Jennings Lane
- Fayetteville NC 28303
- (919) 868-3471
-
- Released to the public domain. For MS-DOS systems and Turbo Pascal.
- }
- {Methods to provide integer addition for huge numbers ..
-
- Presently limited by Turbo Pascal's limitation of string
- variables to 255 bytes.
-
- You COULD use an array for this, extending the length of
- your number string to available memory!
-
- String must be in Data Segment, and should be of the
- format '0000001' or '003270' or whatever.
-
- YES, it MUST be zero-filled, and NO commas or decimals!
- (We're talking multi-character integers here, remember.)
-
- }
-
- TYPE
- Str20 = STRING[20];
- var
- NrStr,
- IntStr : Str20;
- i,code : INTEGER;
-
-
- PROCEDURE Addit;
- {adds two integer strings together.}
- BEGIN
- Inline(
- $1E { push DS}
- /$07 { pop ES ;ES=DS}
- /$31/$DB { xor BX,BX ;clear msbs}
- /$89/$D9 { mov CX,BX}
- /$8A/$0E/>NrStr { mov CL,[>NrStr] ;the shorter number}
- /$E3/$2B { jcxz Exit ;no length, forget it}
-
- /$8A/$1E/>IntStr { mov BL,[>IntStr] ;string length}
- /$8D/$B7/>IntStr { lea SI,>IntStr[BX] ;first char}
- /$89/$F7 { mov DI,SI ;source=destination}
-
- /$88/$CB { mov BL,CL ;NrStr length again}
- /$8D/$9F/>NrStr { lea BX,>NrStr[BX] ;point to last char}
- /$51 { push CX ;save IntStr length}
- /$56 { push SI ;and offsets}
- /$F8 { clc}
- /$FD { std ;direction right to left}
- /$B4/$00 {B20: mov AH,0 ;clear AH}
- /$AC { lodsb ;load IntStr byte}
- /$12/$07 { adc AL,[BX] ;add NrStr val}
- /$37 { aaa ;adjust for Ascii}
- /$AA { stosb ;store sum in IntStr}
- /$4B { dec BX ;back up NrStr}
- /$E2/$F6 { loop B20}
- /$88/$25 { mov [DI],AH ;at end, store carry}
- /$5E { pop SI ;back to the end again}
- /$89/$F7 { mov DI,SI ;source=destination}
- /$59 { pop CX ;get back NrStr length}
- /$41 { inc CX ;anticipate the carry}
- /$AC {B30: lodsb ;snarf the new val}
- /$0C/$30 { or AL,$30 ;ascify it}
- /$AA { stosb}
- /$E2/$FA { loop B30}
- {exit:}
- );
- END;
-
- {Another method:
- Lets you add an integer to ANY global string variable.
-
- Both the integer to be added, and the address of the
- string variable are brought in as parameters.
- }
-
- PROCEDURE Add(nr : INTEGER; VAR S : Str20);
- {could also be:
- PROCEDURE Add(nr : INTEGER; VAR S);
- using Turbo's untyped parameter capability.
-
- use a string variable S brought in as a parameter,
- and the integer nr, also brought in as a parameter.
- }
- BEGIN
- Inline(
- $8B/$86/>NR { mov AX,>nr[BP] ;nr of spins}
- /$09/$C0 { or AX,AX ;anything there?}
- /$74/$27 { je X1 ; nope, quit this mess}
- /$8B/$9E/>S { mov BX,>S[BP] ;snarf the string address.}
- { ;(LDS or LES would also work,}
- { ;but we're assuming S is a global}
- { ;variable .. makes it much simpler.)}
- /$89/$DF { mov DI,BX ;offset to S}
- /$43 { inc BX ;bump past length byte}
- /$31/$C9 { xor CX,CX ;clear msb}
- /$8A/$0D { mov CL,[DI] ;get our integer string length}
- /$01/$CF { add DI,CX ;point to the last char in the string}
- {;}
- /$BE/$0A/$00 { mov SI,10 ; put divisor in SI}
- /$31/$D2 {L1:xor DX,DX ; clear dividend high word}
- /$80/$2D/$30 { sub byte ptr [DI],'0' ;deasciize the char}
- /$02/$05 { add AL,[DI] ;add our integer msb to the char val}
- /$F7/$F6 { div SI ; AX = (DX:AX)/SI, DX = remainder}
- /$80/$C2/$30 { add DL,'0' ; convert DL remainder byte to ascii}
- /$88/$15 { mov byte ptr [DI],DL ; put back in string as char}
- /$4F { dec DI ; back step in string}
- /$39/$DF { cmp DI,BX ;hit start?}
- /$76/$04 { jbe X1 ; yep, done}
- /$09/$C0 { or AX,AX ; all done? (AX = 0?)}
- /$75/$E9 { jne L1 ; if not, do another digit}
- ); {X1:}
- END; {of Add}
-
- {A third method, assuming you'll only have ONE global
- string variable you'll ALWAYS use for this adding.
- (In this demo, that's IntStr.)
- Saves a little time by not having to pass another parm.
- }
-
- PROCEDURE Add_Int(nr : INTEGER);
- { use a global string variable (in this case, IntStr),
- and the integer nr, brought in as a parameter.
- }
- BEGIN
- Inline(
- $8B/$86/>NR { mov AX,>nr[BP] ;nr of spins}
- /$09/$C0 { or AX,AX ;anything there?}
- /$74/$26 { je X2 ; nope, quit this mess}
- /$BB/>IntStr { mov BX,>IntStr ;snarf the string address.}
- {;or could be}
- {; lea BX,>IntStr}
- {;(LDS or LES would also work, but we're assuming}
- {; IntStr is a global variable .. makes it much}
- {; simpler, and we don't chance messing up DS.)}
- /$89/$DF { mov DI,BX ;offset to IntStr}
- /$43 { inc BX ;bump past length byte}
- /$31/$C9 { xor CX,CX ;clear msb}
- /$8A/$0D { mov CL,[DI] ;get our integer string length}
- /$01/$CF { add DI,CX ;point to the last char in the string}
- {;}
- /$BE/$0A/$00 { mov SI,10 ; put divisor in SI}
- /$31/$D2 {L2:xor DX,DX ; clear dividend high word}
- /$80/$2D/$30 { sub byte ptr [DI],'0' ;deasciize the char}
- /$02/$05 { add AL,[DI] ;add our integer msb to the char val}
- /$F7/$F6 { div SI ; AX = (DX:AX)/SI, DX = remainder}
- /$80/$C2/$30 { add DL,'0' ; convert DL remainder byte to ascii}
- /$88/$15 { mov byte ptr [DI],DL ; put back in string as char}
- /$4F { dec DI ; back step in string}
- /$39/$DF { cmp DI,BX ;hit start?}
- /$76/$04 { jbe X2 ; yep, done}
- /$09/$C0 { or AX,AX ; all done? (AX = 0?)}
- /$75/$E9 { jne L2 ; if not, do another digit}
- ); {X2:}
- END; {of Add_Int}
-
-
- PROCEDURE Continue;
- VAR ch : CHAR;
- BEGIN
- Write('Press any key to continue: ');
- Repeat until keypressed; read(kbd,ch);
- Writeln;
- END;
-
- begin
- NrStr := '004';
- IntStr := '00000000000000000000';
- Writeln('First add one number string [',NrStr,']');
- Writeln('to a second number string [',IntStr,']');
- Write(IntStr, ' + ', NrStr, ' = ');
- Addit;
- Writeln(IntStr);
- Continue;
-
- Writeln('Now, add an integer to a number string:');
- FOR i := 1 TO 10 DO BEGIN
- Write(IntStr, ' + ', i:2, ' = ');
- Add(i,IntStr);
- Writeln(IntStr);
- END;
- Continue;
-
- Writeln('Same process, but using the number string as a global:');
- FOR i := 1 TO 10 DO BEGIN
- Write(IntStr, ' + ', i:2, ' = ');
- Add_Int(i);
- Writeln(IntStr);
- END;
- Continue;
-
- Writeln('Flashy, user-friendly interactive demo.');
- Writeln('Enter a positive number string (up to 19 chars).');
- Writeln('(Enter a null line (CR) to quit): ');
- Repeat
- Readln(NrStr);
- IF length(NrStr) > 19 THEN NrStr[0] := #19; {truncate}
- IF NrStr <> '' THEN BEGIN
- Write(IntStr, ' + ', NrStr, ' = ');
- Addit;
- Writeln(IntStr);
- END;
- Until NrStr = '';
- end.
-