home .. forth .. colorforth mail list archive ..

Re: [colorforth] Euler Project Problems.


Dear John. Albert,
Ray here...


> my guess is  0 constant U>D
>
>>
> -John Rible

Thank you, John! That starts to make sense now.


Even after my attempts to fix this application, the example
" FACTORISE 123456" returns the "Not a decimal number" abort.

I was hoping, nay praying, that one of you fine gentilemen might be
able to just 'SEE' the problem ( in the post script below) and hint me
into the proper direction.

Still looking, myself.

Thanks in advance

Ray


-- 
Raymond St. Marie ii,
colorforthray.info



( * The van der Horst Algoritme in Forth.                             * )

(   The "van der Horst" algorithme is a small example program that      )
(   finds a factorization of numbers.                                   )
(   The input number can be very large indeed, large enough that the    )
(   algorithm becomes totally impractical. [State of the art factoring  )
(   uses elliptic curves or quadratic polynomial sieves]                )

(   It is based on a very well known base conversion routine and the    )
(   observation that if you have given a number in base ``b'', its      )
(   divisibility by ``b'' can be established by inspecting the last     )
(   digit of the number.
(   Example : is 97321087 divisible by 10? Answer : no.                 )
(   The base conversion rewrites the number from one base to the next   )
(   and so on with only a small number of additions.                    )
(   Some lack of modesty is needed to call this combination a new       )
(   algorithm and put your name on it.                                  )

(   Author : Albert van der Horst/Adrie Bos/Marcel Hendrix              )
(   Rewritten as a pure ANSI forth example by Albert van der Horst      )

DECIMAL

MARKER -horst \ " versie 5.0 --- ANSI version (LC infinite precision)"

1  VALUE PRECISION        \ Digit length. How many cells is one digit?

0 CONSTANT U>D \ Added for ANS compatability by RAS 080519.

( This is a special array                                               )
( By adjusting PRECISION we can change the length of the elements       )
( A digit is big-endian, a is the array of digits little-endian         )
: LARGE-NUMBER   ( number of elements --- )
     CREATE CELLS ALLOT       ( Make it )
     DOES>  ( Usage: index array.address --> element.address )
            SWAP PRECISION * CELLS +
;

  \ 48  CONSTANT &0              \ Ascii value of '0'
   30  CONSTANT &0              \ real ASCII VALUE OF '0' RAS
   51  CONSTANT &Q              \ ADDED by RAS 080519 fixes .N below

   ( DATA STRUCTURES                                                     )

1000 CONSTANT MAX.BITS          \ Maximum number of bits handled

( ################# tools ########################################      )

( Increment the multiple precision digit at A, big-endian!              )
: increment.digit       ( addr A -- )
    BEGIN
        1 OVER +!
    DUP @ 0= WHILE
        1 CELLS +
    REPEAT
    DROP
;

( Decrement the multiple precision digit at A, big-endian!              )
: decrement.digit       ( addr A -- )
    BEGIN
        -1 OVER +!
    DUP @ -1 = WHILE
        1 CELLS +
    REPEAT
    DROP
;

( Returns "the multiple precision digit at A is zero", big-endian!      )
: DIGIT=0?             ( addr A -- flag )
    PRECISION CELLS BOUNDS DO
       I @ IF UNLOOP FALSE EXIT THEN
    1 CELLS +LOOP
    TRUE
;

\ Subtract more significant digit at addres S from the one at D
\ with borrow (in B1)
\ Leave the borrow B2.
: subtract.digit  ( borrow B1, addr S, addr D - borrow B2 )
\    LOCAL dst Changed for ANS compatablility
\    LOCAL src
    LOCALS| dst src |
    PRECISION 0 DO
       S>D                      \ Borrow
       dst @ U>D D+             \ Add
       src @ U>D D-             \ Subtract
       SWAP dst !               \ Store l.s word, leave borrow
       1 CELLS +TO dst
       1 CELLS +TO src
    LOOP
;

\ Add digit at addres S to the one at D.
: add.digit  ( addr S, addr D - )
\    LOCAL dst Changed for ANS compatablility
\    LOCAL src
    LOCALS| dst src |
    0
    PRECISION 0 DO
       U>D                      \ Carry
       dst @ U>D D+             \ Add
       src @ U>D D+             \ Add
       SWAP dst !               \ Store l.s word, leave carry
\        cr ." leaving a carry of " DUP .
       1 CELLS +TO dst
       1 CELLS +TO src
    LOOP
    DROP                        \ Carry
;

\ Copy digit from addres S to address D.
\ Copying starting at higher addresses, because otherwise sometimes
\ there will be overlaps.
: copy.digit  ( addr S, addr D - )
    LOCALS| dst src |
    PRECISION CELLS + TO dst \ LOCAL dst Changed for ANS compatablility
    PRECISION CELLS + TO src \ LOCAL src
    PRECISION 0 DO
       -1 CELLS +TO dst
       -1 CELLS +TO src
       src @ dst !
    LOOP
;

\ Store the number N as a digit at address A.
: digit!  ( int N, addr A - )
    SWAP OVER !
    PRECISION 1 ?DO
       0   OVER I CELLS +   !
    LOOP
    DROP
;

( The number to be factored is represented as follows :                 )
\ num = sum(i from 0 to length-1 : num[i]*current.base^(len-1-i) )
( or in more mundane parlance :                                         )
( the lowest `length' cells of `num' represent digits in base           )
( `current.base', lowest are the most significant digits                )
CREATE current.base     MAX.BITS ALLOT
VARIABLE length
MAX.BITS LARGE-NUMBER num

\ Detect trouble: the guard bit of the base is incremented, so the
\ current precision is no longer sufficient.
: trouble?      ( -- flag F)
    current.base PRECISION CELLS + @
;

\ Change the way a digit is represented by adding one more cell
\ for each digit in `current.base' as well as `num'
: increase.precision ( -- )

    \ Copy digits up in memory, starting at high addresses (!)
    0 LENGTH @ 1- DO
        I num     DUP I CELLS +   copy.digit
    -1 +LOOP

    1 +TO PRECISION

    \ Initialise the extra cell to each digit to zero
    LENGTH @ 0 DO
        0   I num PRECISION 1- CELLS +    !
    LOOP
    \ And the guard cell in current.base
    0   current.base PRECISION CELLS + !
;

( Print the current base. This is done, whenever a last digit is zero,  )
( such that the current base is factored out.                           )
: ?current.base
    PRECISION 1 = IF
        current.base @ U.
    ELSE PRECISION 2 = IF
        current.base 2@ SWAP UD.
    ELSE        \ We have no easy means to print a 3-CELL number, so...
        ." HEX "
        PRECISION 0 DO current.base I CELLS + @ H. LOOP
    THEN THEN
;

: .N
    KEY? IF
        CR ." base " ?current.base
        CR ." length " length @  .  ."  Digits : "
        length @ 0 ?DO I num @ . LOOP
        \   BREAK? IF THEN
        KEY &Q = ABORT" Terminated by user"
        CR ." Continuing"
    THEN
;

( Before and after HORST the number represented by `num' is the same.   )
( Only `current.base' is one higher than before.                        )
( At point one `num' is in a "mixed base" representation with the       )
( I left most digits in the new base and the remainder still in the     )
( old base, throughout representing the same number.                    )
( See also Knuth: The art of computer programming page 306 :            )
( a "Hand calculation" for going from octal to decimal.                 )
( Only ours is even simpler because our bases differ by 1 not by 2      )
: HORST ( --- )
    .N
    current.base increment.digit         \ Next number base
    trouble? IF increase.precision THEN
    length @ 1 ?DO     ( point one )
          0             \ Borrow
          1 I DO
             I 1 - num   I num   subtract.digit  \ with borrow !
             DUP IF                   \ Borrow? Also leave it
                current.base   I num   add.digit
             THEN
          -1 +LOOP
          ( Last borrow ) IF
              0 num decrement.digit
          THEN
    LOOP
\     .S
;


( Simplifies the number by eliminating leading zero digits              )
: SIMPLIFY ( --- )
     BEGIN
           length @   1   >        \ Prevent wrap around loop for length 1 or 0
           0 num DIGIT=0?
           AND
     WHILE
           length @ 1 DO     \ Shift to the right
              I num   I 1- num   copy.digit
           LOOP
           -1 length +!         \ One shorter now
     REPEAT
;


( Convert the number to the next higher base                      )
: NEXT.FACTOR ( --- )
     HORST
     SIMPLIFY
;


( Store the 4 bits of <word> at 4 successive lower addresses beneath    )
( <adr1>. The last address used is returned.                            )
( Least significant bit is stored highest.                              )
: SPLIT4 ( adr1 word --- adr2 )
     SWAP
     4 0 DO                     \ For all 4 bits:          )
          1- >R                 \ Decrement and store index)
          2 /MOD SWAP           \ Split off right most bit )
          R@ num digit!          \ Store it           )
          R>                    \ Get index back
     LOOP
     SWAP DROP                  \ Drop the remainder
;


( Convert the decimal number as given to binary.                        )
( Apply HORST 6 times for base 16.                                      )
( Then each digit contains 4 bits of the number,                        )
( split them over 4 cells.                                              )
: DECIMAL.TO.BINARY ( --- )
     6 0 DO NEXT.FACTOR LOOP    \ Now in HEX
     length @ 4 *               \ Point after last cell of binary representation
     0 length @ 1- DO           \ From the end to prevent overwrites
          I num @               \ Hex digit I
          SPLIT4                \ distribute the bits
     -1 +LOOP

     length @ 4 *
     length !                   \ 4 times as much digits
     2 current.base digit!           \  `num' is binary now

     SIMPLIFY                   \ Rid of leading zero's
     length @ 1 =               \ But not of the last one,
     0 num DIGIT=0?             \  because of looping finesses
     AND ABORT" Zero cannot be factored"
;

: ASCII->BINARY ( char --- double )
( Convert a character digit to a binary representation                  )
     &0 -
     DUP 0< OVER 9 > OR ABORT" Not a decimal number"
;

: READ.DECIMAL.NUMBER           \ ( --- >> "number.string" )
     1 TO PRECISION             \ Reset precision
     BL WORD                    \ get from input
     COUNT                      \ String.address length
     DUP 0= ABORT" Please input a number"
     DUP length !               \ Remember!
     0 DO                       \  Convert each digit
          C@ \ C@+ is this a typing error? RAS 080519
          ASCII->BINARY
          I num digit!          \  to binary in number.
     LOOP DROP                  \  Drop string address.
     10 current.base digit!     \ Start with decimal
     0 current.base CELL+ !     \ Guard decimal for the overflow
;

( Print the remaining factor.                                           )
( Depending on the circumstances the number may have 1 or 2             )
( digits. It is always prime, because smaller numbers have been         )
( factored out. If it is 1 it is not printed, of course.                )
: LAST.FACTOR ( --- )
     length @ 1 = IF
        \ The single digit must be 1 in this case
        0 num @ DUP 1 <> ABORT" Unexpected remainder"
     ELSE
        PRECISION 1 = IF
            ( Calculate the number represented by `num' )
            ( Double precision is sufficient )
            0 num @   current.base @   UM*
            1 num @   U>D   D+
            CR ." Factor: " UD.
        ELSE
            CR ." Factor: too large too print"
        THEN
     THEN
;

( It is well known that we need not look for factors in a number        )
( that are larger than its square root.                                 )
( In the representation choosen this means that it need less than 2     )
( digits to be represented. The flag indicates there may be factors to  )
( be found.                                                             )
: NOT.PAST.SQUARE.ROOT ( --- flag )
          2 length @ <
;


( The number `num' is divisable by base if the last digit is zero       )
( The flag indicates whether `num' is divisable by `current.base'       )
: ?DIVISABLE ( --- flag )
               length @ 1- num DIGIT=0?
;

( And finally ......                                                    )

( `FACTORISE' accepts a string in the input stream with decimal digits  )
( and factorises it.                                                    )
: FACTORISE
     READ.DECIMAL.NUMBER
     DECIMAL.TO.BINARY
     BEGIN
        NOT.PAST.SQUARE.ROOT WHILE
          BEGIN
             ?DIVISABLE WHILE
                CR ." Factor: " ?current.base
                -1 length +!    \ This divides by factor, scrap the last 0
          REPEAT
          NEXT.FACTOR           \ Base conversion
     REPEAT
     LAST.FACTOR                \ Print the last factor
;

: .HELP ." USAGE : FACTORISE 123456 <Return> "             ;

---------------------------------------------------------------------
To unsubscribe, e-mail: colorforth-unsubscribe@xxxxxxxxxxxxxxxxxx
For additional commands, e-mail: colorforth-help@xxxxxxxxxxxxxxxxxx
Main web page - http://www.colorforth.com