一百個例題 (35 ~ 36)
Ching-Tang Tseng
Hamilton, New Zealand
4 September 2024
\ (35)萬用局部變數.f \ postfix style local variables : EraseName ( cfa -- ) dup ['] empty u< if cr abort" is a system word can not to be localize!" then >name dup c@ 1+ 0 fill ; : localize ( -- ) [compile] ' EraseName ; localize EraseName : localizes ( n -- ) 0 ?do localize loop ; \ ************************************* 4 integers i a b c : tt1 basic 10 let a = 1 :: b = 2 :: c = 3 20 for i = 1 to 2 30 print a , b , c 40 next i 50 end ; localize i 2 localizes a b \ ************************************* 3 integers i a b : tt2 basic 10 let a = 7 :: b = 8 20 for i = 1 to 3 30 run tt1 40 print a , b , c 50 next i 60 end ;
\ (36) iForth版大數四則運算程式 (* * LANGUAGE : ANS Forth * PROJECT : Forth Environments * DESCRIPTION : Big number package * CATEGORY : Utility * AUTHOR : Marcel Hendrix November 17, 1991 * LAST CHANGE : October 10th, MHX: some old names updated. Retested (some). * LAST CHANGE : Jan 5th, 1992, MHX : bugs in .VNUM if remainder = 0 (?) * LAST CHANGE : November 18, 1991, Ideas of Albert van der Horst: I/O. * LAST CHANGE : November 10, 1991, Ideas of Albert van der Horst: Vsqrt. * LAST CHANGE : November 2, 1991, Marcel Hendrix, changed order * LAST CHANGE : AH 911231: assembler codes/macros cleanup * LAST CHANGE : November 18, 1991, Marcel Hendrix * LAST CHANGE : March 18, 2001, Marcel Hendrix, adapted to iForth 1.11e. NEEDS TESTING * LAST CHANGE : March 24, 2001, Marcel Hendrix, removed bugs in .VNUM V<< and V>> , removed UM- *) NEEDS -miscutil REVISION -bignum "?? BigNumber Toolkit Version 2.00 ??" PRIVATES DOC BIGNUM (* A bignum is like an ARRAY, but the parameter field is allocated dynamically, so we have to keep pointers to it. Furthermore, the digit string does NOT start at the beginning of the allocated area, but is right-aligned. Carefully note that a `digit' takes a full cell! In the administration field of a BIGNUM the following can be found: offset (cells) comment -------------------------------------------------------------------- 0 the maximum string size in bytes 1 pointer to the first digit of the number string 2 pointer to the last digit of the number string 3 the start address of the allocated area BIGNUM BODY : [#size][^head][^tail][^begin] | | | +-----------------------------+ | | | | | +---------------------+ | | | v v v [ ][ ][ ][ ][ ][ ][ ][ ][*][ ][ ... ][*][ ][ ][ ] 0 1 2 3 4 ... -3 -2 -1 0 <-------------------[ size ]--------------------> In the algorithms needed to process bignums, it is convenient to be able to address relative to both the head and the tail of the digit string. This can be accomplished using the TO concept and three additional modifiers; #DIGITS, HEAD and TAIL . { 3 TO 4 HEAD number } means: 3 head_of_number @ 4 CELLS + ! { CLEAR 6 TAIL number } means: tail_of_number @ 6 CELLS - 0! { 'OF number } means: begin_of_number { 1 +TO #DIGITS number } means: -1 head_of_number +! *) ENDDOC -- Utility -- -- Normalize a number, how many left shifts are needed to make the msb = '1' : FRONT.ZEROES ( n -- 31-log2 ) #31 -1 ROT ( log2 n) DUP $FFFF0000 AND IF #16 UNDER+ #16 RSHIFT ENDIF DUP $0000FF00 AND IF 8 UNDER+ 8 RSHIFT ENDIF DUP $000000F0 AND IF 4 UNDER+ 4 RSHIFT ENDIF DUP $0000000C AND IF 2 UNDER+ 2 RSHIFT ENDIF DUP $00000002 AND IF 1 UNDER+ 1 RSHIFT ENDIF 1 AND + - ; ( log2) : '[] 6 %VAR ! ; IMMEDIATE \ same as ADDR (arrays.frt) : 'LASTOF 7 %VAR ! ; IMMEDIATE \ address of last element : HEAD %VAR @ $10 + %VAR ! ; IMMEDIATE : TAIL %VAR @ $20 + %VAR ! ; IMMEDIATE -- The #DIGITS modifier is used to manipulate a BIGNUM's head pointer : #DIGITS %VAR @ $30 + %VAR ! ; IMMEDIATE : ADMIN, SWAP []CELL ALITERAL ; PRIVATE \--- : ADMIN@, SWAP []CELL @ ALITERAL ; PRIVATE \ --- : NEG-2-ADMIN, >S ['] NEGATE NOW? \ --- <> S> 2 ADMIN, ; PRIVATE : SIZE@ EVAL" CELL+ 2@ - #CELLS 1+ " ; \ <'admie> --- <#elements> IMMEDIATE : SIZE+! SWAP CELLS SWAP CELL+ -! ; \ <'admie> --- <> : SIZE! 2 CELLS + @- CELL+ \ <'admie> --- <> ROT CELLS - SWAP ! ; -- Note that 'HEAD@ etc. should not be stored as pointers: some -- routines change the size and/or location of a BIGNUM ( see REPACK ) : 'HEAD@ \ <'admie> --- <'head> EVAL" CELL+ @ " ; IMMEDIATE : 'TAIL@ \ <'admie> --- <'tail> EVAL" 2 SWAP []CELL @ " ; IMMEDIATE : []TAIL \ <'admie> --- EVAL" 'TAIL@ SWAP NEGATE SWAP []CELL " ; IMMEDIATE : []HEAD \ <'admie> --- EVAL" 'HEAD@ []CELL " ; IMMEDIATE : CLEAR-BIGNUM >S \ <'adm> --- <> 3 S []CELL @ \ 'OF number S @ ERASE \ SIZEOF number 2 S []CELL @ CELL+ \ 'LASTOF number + 1 S> CELL+ ! ; \ adjust HEAD of number : VVmove >S DUP @ >R \ <'bignum1> <'bignum2> --- <> 3 OVER []CELL @ 3 S []CELL @ \ 'OF_1 'OF_2 R> S @ <> ABORT" source and destination differ in length" S @ MOVE \ size_2 move >S 2 T []CELL @ \ 'last1 + 1 1 S> []CELL 2@ - - \ - ( elements1 + 1) 1 S> []CELL ! ; \ store in head2 -- Note the sometimes subtle differences between an ARRAY and -- a BIGNUM ( /OF number is not a constant) : CELLS DUP , \ --- <> DUP ALLOCATE ?ALLOCATE ( count addr) 2DUP + DUP ( head) , CELL- ( tail) , DUP ( begin address) , SWAP ERASE ; : BIGNUM \ BIGNUM # # CREATE IMMEDIATE FORGET> DUP 3 CELLS + @ FREE SWAP 4 CELLS ERASE ?ALLOCATE DOES> %VAR @ 0 %VAR ! \ without HEAD or TAIL : access head or tail CASE \ ( +to) -1 OF ALITERAL ['] +BIGNUM NOW? ENDOF ( from) 0 OF ALITERAL ENDOF ( to) 1 OF ALITERAL ['] VVmove NOW? ENDOF ( clear) 2 OF ALITERAL ['] CLEAR-BIGNUM NOW? ENDOF ( 'of) 3 OF 3 ADMIN@, ENDOF ( sizeof) 4 OF @ ILITERAL ENDOF ( /of) 5 OF 1 ADMIN, EVAL" 2@ - #CELLS 1+ " ENDOF \ ( '[]) 6 OF ENDOF ( 'last) 7 OF 2 ADMIN@, ENDOF ( +h) #15 OF 1 ADMIN, EVAL" @ []CELL +! " ENDOF ( h@) #16 OF 1 ADMIN, EVAL" @ []CELL @ " ENDOF ( h!) #17 OF 1 ADMIN, EVAL" @ []CELL ! " ENDOF ( h0!) #18 OF 1 ADMIN, EVAL" @ []CELL OFF " ENDOF ( h'[]) #22 OF 1 ADMIN, EVAL" @ []CELL " ENDOF ( +t) #31 OF NEG-2-ADMIN, EVAL" @ []CELL +! " ENDOF ( t@) #32 OF NEG-2-ADMIN, EVAL" @ []CELL @ " ENDOF ( t!) #33 OF NEG-2-ADMIN, EVAL" @ []CELL ! " ENDOF ( t0!) #34 OF NEG-2-ADMIN, EVAL" @ []CELL 0! " ENDOF ( t'[]) #38 OF NEG-2-ADMIN, EVAL" @ []CELL " ENDOF ( +to) #47 OF 1 ADMIN, EVAL" >S CELLS S> -! " ENDOF ( from) #48 OF 1 ADMIN, EVAL" 2@ - #CELLS 1+ " ENDOF ( to) #49 OF ALITERAL ['] SIZE! NOW? ENDOF ( clear) #50 OF 2 ADMIN, EVAL" @- CELL+ SWAP ! " ENDOF ( 'of) #51 OF 1 ADMIN, ENDOF \ ( szeof) #52 OF DROP 1 ILITERAL ENDOF \ ( /of) #53 OF DROP 1 ILITERAL ENDOF \ ( '[]) #54 OF 1 ADMIN, ENDOF ( 'last) #55 OF 2 ADMIN@, ENDOF DUP ABORT" BIGNUM: undefined message" ENDCASE ; : REPACK \ <'admin> --- <> LOCAL num BEGIN \ throw away leading zeros. num SIZE@ 0<> \ still digits? num 'HEAD@ @ 0= AND \ ..and leading 0? WHILE -1 num SIZE+! \ throw away. REPEAT ; =CELL 8 * =: BITS/CELL #1500 =: MAX.DIGITS -- superdigits! DOC Big number manipulations. (* In the following, "V" means the address of a Vnum, "u" is an unsigned single precision Forth number. Stack diagram ( V u -- ) VS- subtract u from V (in place) VS+ add u to V (in place) VS* multiply V with u (in place) Stack diagram ( V u1 -- u2 ) VS/MOD as /MOD , quotient in V, remainder in u2 Stack diagram ( V -- ) VSqrt Calculate the largest number whose square is smaller than V, put it in SS. Stack diagram ( V1 V2 -- ) VVmove copy V1 to V2 VV- subtract V2 from V1 (in place) VV+ add V2 to V1 (in place) VV* multiply V1 and V2, result to PP VV/MOD as /MOD , quotient in QQ, remainder in RR VGCD greatest common divisor of V1 and V2, result in SS Most are straightforward. VV* benefits from the formula : (Knuth part 3 pg. 278) ( 2?*u1+u0)*(2?*v1+v0) = ( 2?+2?)*u1*v1 + 2?*(u1-u0)*(v1-v0) + (2?+1)*u0*v0. (saves 1 out of 4 multiplications) VV/MOD can be implemented as a normal tail division, i.e. find a single precision multiplier D for V2 such that subtracting D*V2 from the front of V1 makes it first cell zero, so D is the first cell of the quotient. Contrary to the expectation, this is about the best you can do. VGCD can be implemented using VV/MOD but an add and shift algorithm is probably faster. *) ENDDOC -- Returns the number of the MSB (32..1), in the number U. : SCOUNT-BITS \ -- DUP 0= IF EXIT ENDIF \ infinite loop 0 BEGIN 1+ SWAP 1 RSHIFT DUP WHILE SWAP REPEAT DROP ; -- Returns the number of bits in the Vnumber V : VCOUNT-BITS \ --- >S S SIZE@ DUP IF 1- BITS/CELL * S> 'HEAD@ @ SCOUNT-BITS + \ Get first cell ELSE -S ENDIF ; -- Add u to V in place. No bounds check; if carry -> 1 digit longer. -- We assume the least significant digit is at the highest memory address. -- V is assumed positive. : VS+ LOCAL carry \ --- <> LOCAL V V 'TAIL@ V SIZE@ 0 ?DO @- carry UM+ TO carry OVER CELL+ ! LOOP carry ?DUP IF SWAP ! 1 V SIZE+! EXIT ENDIF DROP ; -- Subtract u from V in place. The number may become 1 digit shorter. : (VS-) LOCAL u \ --- 0 LOCAL borrow LOCAL V V 'TAIL@ V SIZE@ 0 ?DO @- borrow SWAP u UM- TO borrow OVER CELL+ ! CLEAR u LOOP CELL+ @ 0= IF -1 V SIZE+! ENDIF borrow ; : VS- (VS-) IF CR ." VS- : Overflow " \ --- ENDIF ; -- Test if the Vnumber is 0. : VS0= SIZE@ 0= ; \ --- -- store n in BIGNUM : V! DUP CLEAR-BIGNUM \ --- <> SWAP VS+ ; -- VS= compares the Vnumber with a single i : VS= \ --- ?DUP IF SWAP >S S SIZE@ 1 = \ Length = 1 ? SWAP S> 'TAIL@ @ = \ Content ok ? AND ELSE VS0= ENDIF ; -- multiply V with u in place. The length of the result can be zero, equal, or -- 1 digit larger. : VS* DUP 0= IF DROP CLEAR-BIGNUM \ --- <> EXIT ENDIF LOCAL u 0 LOCAL carry LOCAL V V 'TAIL@ V SIZE@ 0 ?DO @- u UM* carry U>D D+ TO carry OVER CELL+ ! LOOP carry ?DUP IF SWAP ! 1 V SIZE+! EXIT ENDIF DROP ; -- as MOD, remainder in u2, V untouched : VSMOD OVER SIZE@ 0= OVER 0= OR \ -- IF 2DROP 0 EXIT ENDIF \ already zero or div by 0? 0 LOCAL carry LOCAL u1 LOCAL V V 'HEAD@ \ '(latest digit) V SIZE@ FOR AFT @- carry u1 UM/MOD DROP TO carry THEN NEXT DROP carry ; -- as /MOD , quotient in V, remainder in u2. 1 <= New length of V <= old len. : VS/MOD OVER SIZE@ 0= OVER 0= OR \ --- IF 2DROP 0 EXIT ENDIF \ already zero or div by 0? 0 LOCAL carry LOCAL u1 LOCAL V V 'HEAD@ \ '(latest digit) V SIZE@ FOR AFT @+ carry u1 UM/MOD SWAP TO carry OVER CELL- ! THEN NEXT DROP V REPACK carry ; -- Give a Vnum at least u digits by extending it with zeros. -- Count is adjusted! : Vextend SWAP LOCAL V \ --- <> V SIZE@ - 0 MAX 0 ?DO 1 V SIZE+! 0 V 'HEAD@ ! LOOP ; -- Shift a Vnum up over u bit positions. ( u <= bits/word) : [V<<] 0 LOCAL carry \ --- <> LOCAL places LOCAL V V 'TAIL@ V SIZE@ 0 ?DO @- U>D places DLSHIFT carry U>D D+ TO carry OVER CELL+ ! LOOP carry IF carry SWAP ! 1 V SIZE+! EXIT ENDIF DROP ; -- Shift a Vnum up over u bit positions. : V<< ( V u -- ) BITS/CELL /MOD LOCALS| n1 n2 V | V n2 [V<<] n1 0 ?DO V BITS/CELL [V<<] LOOP ; -- Shift a Vnum down over u bit positions. ( u <= bits/word) : [V>>] 0 LOCAL carry \ --- <> LOCAL places LOCAL V V 'HEAD@ V SIZE@ 0 ?DO @+ 0 SWAP places DRSHIFT 0 carry D+ SWAP TO carry OVER CELL- ! LOOP DROP V REPACK ; : V>> ( V u -- ) BITS/CELL /MOD LOCALS| n1 n2 V | V n2 [V>>] n1 0 ?DO V BITS/CELL [V>>] LOOP ; -- Convert Vnum to binary `exponent, mantissa format', where the maximum -- exponent is 32 (cell width in bits). : VNORMALIZE LOCAL V \ --- V SIZE@ 0= IF 0 EXIT ENDIF V 'HEAD@ @ FRONT.ZEROES \ highest word V OVER V<< ; -- Convert `exponent, mantissa format' to Vnum : VUNNORMALIZE V>> ; \ --- <> -- Add V2 to V1 in place. V1 may grow to max(V1,V2)+1. : VV+ 0 LOCAL carry \ --- <> LOCAL V2 LOCAL V1 V1 V2 SIZE@ Vextend \ give them the same length V2 V1 SIZE@ Vextend V1 'TAIL@ LOCAL p1 V2 'TAIL@ LOCAL p2 V2 SIZE@ 0 ?DO p1 @- SWAP TO p1 p2 @- SWAP TO p2 UM+ carry U>D D+ TO carry p1 CELL+ ! LOOP V2 REPACK \ reset length of V2 carry ?DUP IF p1 ! 1 V1 SIZE+! EXIT ENDIF ; -- Subtract V2 from V1 in place. V2 is not modified. 0 <= Length V1 <= V1 : (VV-) 0 LOCAL borrow \ --- LOCAL V2 LOCAL V1 V1 V2 SIZE@ Vextend \ give them the same length V2 V1 SIZE@ Vextend V1 'TAIL@ LOCAL p1 V2 'TAIL@ LOCAL p2 V2 SIZE@ 0 ?DO borrow p1 @- SWAP TO p1 p2 @- SWAP TO p2 UM- TO borrow p1 CELL+ ! LOOP V2 REPACK \ reset length of V2 V1 REPACK borrow ; : VV- (VV-) IF CR ." VV- : overflow " \ --- <> ENDIF ; -- Scratch and input/output variables. MAX.DIGITS BIGNUM PP MAX.DIGITS BIGNUM QQ MAX.DIGITS BIGNUM RR MAX.DIGITS BIGNUM SS -- multiply V1 and V2, result to PP. -- See: `The Art of Computer Programming' Second Edition, Volume 2, -- Seminumerical Algorithms, D. E. Knuth. -- Algorithm M, pp 253-254. : VV* PP LOCAL w \ --- <> LOCAL v v SIZE@ LOCAL m LOCAL u u SIZE@ LOCAL n m 0= n 0= OR IF EXIT ENDIF ( M1. ) w CLEAR-BIGNUM w m n + Vextend 0 LOCAL carry m 0 DO I v []TAIL @ ( M2. ) 0= IF 0 ( M3. ) ELSE CLEAR carry ( M4. ) n 0 DO I u []TAIL @ J v []TAIL @ UM* I J + w []TAIL >S S @ U>D D+ carry U>D D+ TO carry S> ! ( M5. ) LOOP carry ENDIF ( M6. ) I n + w []TAIL ! LOOP w REPACK ; -- Like /MOD . Quotient in QQ, remainder in RR. -- Knuth's Algorithm D. -- U should have at least two digits, u is the size of the largest of the -- strings at a1 and a2. (The other one needs leading zeroes). -- Note that dst and src point to the FIRST digit of superdigit strings! : MUL&SUB LOCAL qhat \ <*> --- ROT LOCAL 'dest 0 LOCAL carry 0 LOCAL borrow >S S CELLS DUP +TO 'dest CELL- + ( src) S> ( u) 0 ?DO @- qhat UM* carry U>D D+ TO carry borrow 'dest @ ROT UM- TO borrow 'dest ! [ =CELL NEGATE ] LITERAL +TO 'dest LOOP DROP borrow 'dest @ carry UM- SWAP 'dest ! ( Leaves borrow ) ; PRIVATE -- Note that a1 and a2 point to the FIRST digit of superdigit strings! -- Note that the carry must be added at the last step! : ADDBACK ROT LOCAL 'dest \ --- <> 0 LOCAL carry >S S CELLS DUP +TO 'dest CELL- + ( src) S> ( u) 0 ?DO @- 'dest @ UM+ carry U>D D+ TO carry 'dest ! [ =CELL NEGATE ] LITERAL +TO 'dest LOOP DROP carry 'dest +! ; PRIVATE \ This ripples .. but cancels -- VV/MOD has already removed trivial or cumbersome cases. WARNING @ WARNING OFF MAX.DIGITS BIGNUM U PRIVATE MAX.DIGITS BIGNUM V PRIVATE : (VV/MOD) TO V TO U \ --- <> 0 LOCAL qhat 0 LOCAL rhat /OF V LOCAL n /OF U n - 1+ LOCAL m+1 CLEAR QQ QQ m+1 Vextend V VNORMALIZE LOCAL exp \ normalize V 0 HEAD V LOCAL V1 1 HEAD V LOCAL V2 \ highest digits of V ( D1. ) U /OF U 1+ Vextend U exp V<< \ normalize U ( D2. ) m+1 0 ?DO ( D3. ) I HEAD U V1 = IF -1 TO qhat ELSE I 1+ HEAD U I HEAD U V1 UM/MOD TO qhat TO rhat ENDIF BEGIN I 2+ HEAD U rhat \ remainder*b + Uj+2 V2 qhat UM* DU< WHILE -1 +TO qhat V1 rhat UM+ SWAP TO rhat UNTIL ( overflow) THEN ( D4. ) I '[] HEAD U 0 '[] HEAD V n qhat MUL&SUB ( borrow) ( D5. ) qhat TO I HEAD QQ ( D6. ) IF -1 +TO I HEAD QQ I '[] HEAD U 0 '[] HEAD V n ADDBACK ENDIF ( D7. ) LOOP ( D8. ) U TO RR n TO #DIGITS RR \ lower n digs of Un+m RR exp VUNNORMALIZE QQ REPACK RR REPACK ; PRIVATE : VV/MOD DUP SIZE@ 0= \ --- <> IF 2DROP \ packed v must have at least CLEAR QQ CLEAR RR \ _two_ superdigits. EXIT ENDIF DUP SIZE@ 1 = \ if size is 1, use VS/MOD IF CLEAR RR SWAP TO QQ QQ SWAP 'HEAD@ @ VS/MOD ?DUP IF RR SWAP VS+ ENDIF EXIT ENDIF OVER SIZE@ OVER SIZE@ \ if U < V we already know. < IF DROP CLEAR QQ TO RR EXIT ENDIF (VV/MOD) ; WARNING ! -- Greatest common divisor of U and V, result in SS -- A1. v = 0 => u is answer -- A2. r <- u mod v, u <- v, v <- r, loop to A1. : VGCD PP VVmove \ -- <> SS VVmove BEGIN PP SIZE@ WHILE SS PP VV/MOD \ RR = remainder PP TO SS \ u <- v RR TO PP \ v <- (u mod v)_old REPEAT ; -- Is V1 equal to V2 ? : VV= >S DUP 'HEAD@ SWAP SIZE@ CELLS \ --- S> DUP 'HEAD@ SWAP SIZE@ CELLS COMPARE 0= ; -- Is V1 less than V2 ? : VV< OVER SIZE@ OVER SIZE@ \ --- 2DUP < IF 2DROP 2DROP TRUE EXIT ENDIF > IF 2DROP FALSE EXIT ENDIF FALSE LOCAL less? 'HEAD@ >S DUP 'HEAD@ SWAP SIZE@ 0 ?DO @+ S> @+ SWAP >S 2DUP <> IF U< IF TRUE TO less? ENDIF LEAVE ELSE 2DROP ENDIF LOOP DROP -S less? ; -- Calculate the largest number whose square is smaller than V, put it -- in SS. We use Newton-Raphson : sqrt(v) = lim n->? An+1=(An+v/An)/2 : VSqrt LOCAL V \ --- <> V TO SS V VS0= IF EXIT ENDIF SS DUP VCOUNT-BITS 1- 2/ V>> \ Use l.s. half of the bits V SIZE@ BITS/CELL * \ bits per word = Too much! 0 ?DO V SS VV/MOD QQ SS VV+ QQ 1 V>> QQ REPACK QQ SS VV= IF LEAVE THEN QQ TO SS LOOP ; MAX.DIGITS BIGNUM IOscratch PRIVATE : n-Group ( I n -- ) LOCAL n U>D <# n 0 ?DO 3 0 ?DO # LOOP ',' HOLD LOOP #> TYPE ; PRIVATE -- Auxiliary routine for .VNUM -- Uses the stack for reversing the order of digits (here a digit=10^9) : x^n ( x n -- x^n ) 1 SWAP 0 ?DO OVER * LOOP NIP ; PRIVATE : (.VNUM) RECURSIVE BASE @ 3 x^n DUP 3 x^n LOCALS| b10^9 b10^3 | /OF IOscratch 1 = IF 0 TAIL IOscratch b10^3 U>= IF IOscratch b10^3 VS/MOD (.VNUM) 1 n-Group ELSE 0 TAIL IOscratch U>D <# #S #> TYPE ENDIF EXIT ENDIF IOscratch b10^9 VS/MOD (.VNUM) 3 n-Group ; PRIVATE : .VNUM ( VV -- ) BASE @ >R DECIMAL DUP REPACK DUP SIZE@ 0= IF DROP ." 0" ELSE TO IOscratch (.VNUM) ENDIF R> BASE ! ; -- VREAD works for any BASE : VREAD ( VV -- ) CLEAR IOscratch BL WORD COUNT 0 ?DO C@+ BASE @ DIGIT? 0= ABORT" Strange character in number" IOscratch BASE @ VS* IOscratch SWAP VS+ LOOP DROP IOscratch SWAP VVmove ; :ABOUT CR ." In the following, `V' means the address of a Vnum," CR ." `u' is an unsigned single precision Forth number." CR CR ." Stack diagram ( V u -- )" CR CR ." VS- subtract u from V (in place)" CR ." VS+ add u to V (in place)" CR ." VS* multiply V with u (in place)" CR ." Vextend add leading zeroes, ensuring V has at least u digits." CR CR ." Miscellaneous operators" CR CR ." V! ( u V -- ) Store u in V" CR ." VS/MOD ( V u1 -- u2 ) as /MOD , quotient in V, remainder in u2" CR ." VS0= ( V -- bool ) test if V is equal to zero." CR ." V<< ( V +n -- ) shift V left over +n bit positions." CR ." V>> ( V +n -- ) shift V right over +n bit positions." CR ." VUNNORMALIZE ( V +n -- ) exponent, mantissa format to Vnum. (*)" CR ." VNORMALIZE ( V -- +n ) Vnum to exponent, mantissa format." CR CR ." (*) The maximum exponent is equal to the number of bits per cell : " BITS/CELL DEC. CR CR ." --more-- " KEY DROP ^M EMIT EOL CR ." Stack diagrams ( v1 v2 -- ) " CR ." --------------------------- " CR CR ." VVmove copy V1 to V2" CR ." VV- subtract V2 from V1 (in place)" CR ." VV+ add V2 to V1 (in place)" CR ." VV* multiply V1 and V2, result to PP" CR ." VV/MOD as /MOD , quotient in QQ, remainder in RR" CR ." VGCD greatest common divisor of V1 and V2, result in SS" CR CR ." VV= ( v1 v2 -- bool ) test for equality CR ." VV< ( v1 v2 -- bool ) test for unsigned less than CR ." VSqrt ( v -- ) Calculate the largest number whose square is" CR ." smaller than v, put it in SS" CR CR ." --more-- " KEY DROP ^M EMIT EOL CR ." INPUT and OUTPUT" CR ." ----------------" CR ." BIGNUM # # ( # # -(exec)-> )" CR ." VREAD # # ( any base )" CR ." .VNUM ( always in decimal ) " CR CR ." NOTE: BigNums have less than " MAX.DIGITS DEC. ." super digits." CR ." NOTE: Define 1 =: testing before loading to compile the example DIV " CR ; DEPRIVE nesting @ 0= [IF] CR .ABOUT -bignum [DEFINED] testing [IF] MAX.DIGITS BIGNUM V1 V1 VREAD 100000000000000000 MAX.DIGITS BIGNUM V2 V2 VREAD 60000000000000000 : DIV CR ." dividend -> " QUERY V1 VREAD CR ." divisor -> " QUERY V2 VREAD V1 V2 VV/MOD CR ." v1 v2 " /OF V1 DEC. /OF V2 DEC. ." pp qq rr ss " /OF PP DEC. /OF QQ DEC. /OF RR DEC. /OF SS DEC. CR CR ." quotient -> " QQ .VNUM CR ." remainder -> " RR .VNUM QQ V2 VV* PP RR VV+ CR ." check -> " PP .VNUM CR ; [THEN] [THEN] (* End of Source *)
沒有留言:
張貼留言