In the search for faster factorials, I previously offered a Qbasic program to illustrate the use of a string. It was never intended to be an example of the finest. In particular, the problem with a high- level language is that hidden things are taking place. In the case of the string, data is stored as ASCII - where every digit has 48 added on in order to create the ASCII of the SYMBOL. Thus, every time the Qbasic programs looks at a digit, it takes 48 away - and every time it stores a digit it adds 48 on. This is a total waste of CPU power. Dana DeLouis contacted me to say that (Dana) had modified that program and achieved impressive speeds. However, Dana did not state the CPU type. I am fully aware that improvements can be made - but if serious power is sought, the way ahead is MACHINE CODE. Here is a machine-code program of less than 400 bytes. Unfortunately, as the British government took everything from me I do not have any reference works - so anybody who is skilled in the art of programming and has time and literature may well improve upon it. It is IBM ONLY: *************************************** offset equ 256 count equ 32400 stringlength equ count+count jmp start words: db 13,"*******************" db 13,10,"* WEHNER`s *" db 13,10,"* FACTORIAL MAKER *" db 13,10,"* COPYRIGHT 2003 *" db 13,10,"*******************$",26 crlf: db 13,10,"$" string: db "STRING OVERFLOW",13,10,"$" maths: db "MATHS OVERFLOW",13,10,"$" topmost: dw 0 lowest: dw 0 factlength: dw 1 overflow: dw 0 evaluate: ;; Evaluate a decimal number xor dx,dx ;; Result in DX cld recycle: lodsb ;; Read a byte sub al,48 ;; Remove ASCII code jc evaluated ;; Done if below 0 cmp al,10 jnc evaluated ;; Done if above 9 xor ah,ah ;; 2-byte number push ax ;; Save mov ax,dx ;; Copy total add ax,ax ;; Times 2 jc finish2 ;; Overflow? add ax,ax ;; Times 4 jc finish2 ;; Overflow? add ax,dx ;; Times 5 jc finish2 ;; Overflow? add ax,ax ;; Times 10 jc finish2 ;; Overflow? pop dx ;; Recover digit add dx,ax ;; Add digit jc finish ;; Overflow? jmp recycle ;; KEEP GOING. evaluated: ;; Return when number ends. ret finish2: ;; Overflow with number to pop ax ;; remove from stack. finish: ;; Overflow. mov dx,maths+offset ;; Point to "MATHS OVERFLOW" abort: mov ax,900h ;; Function 9 int 33 ;; Call system mov ah,76 ;; WARM BOOT. int 33 longstring: ;; ABORT if the factorial mov dx,string+offset ;; is longer than the jmp abort ;; available string space. start: cld ;; Direction up. mov cx,count ;; Count in 2-byte words mov di,factorial2+offset xor ax,ax ;; Nil in AX repz stosw ;; Fill the memory. mov dx,crlf+offset mov ah,9 ;; Display CR and LF int 33 mov si,05dh ;; Read default FCB call evaluate ;; for numerical command tail mov [topmost+offset],dx ;; as TOP of factorial mov si,06dh ;; Read second FCB call evaluate ;; for numerical command tail cmp dx,2 jnc progress mov dx,2 ;; zero and 1 replaced by 2 progress: mov [lowest+offset],dx ;; as BOTTOM of factorial repeating: mov ax,[lowest+offset] mov bx,ax ;; Multiplier in BX. dec ax cmp ax,[topmost+offset] ;; If lowest EXCEEDS top jnc showing ;; no more calculation. DISPLAY. inc ax inc ax mov [lowest+offset],ax ;; Advance the lowest. xor dx,dx mov si,factorial+offset ;; Start at FACTORIAL. mov di,si ;; Source and Dest the same. mov cx,stringlength ;; CX = maximum string space. multiplyloop: lodsb ;; Read a byte of factorial. xor ah,ah ;; Clear top byte. mul bx ;; Multiply by next term. add ax,[overflow+offset] adc dx,0 ;; Add overflow (4-byte) push bx mov bx,10 ;; Divide by 10 div bx pop bx mov [overflow+offset],ax and dl,dl ;; If modulus is not nil, more. jnz more and ax,ax ;; If modulus and overflow nil jz finished? ;; maybe finished. more: mov al,dl ;; Save results stosb loop multiplyloop ;; Loop jmp longstring ;; unless string-space exceeded. showing: mov cx,[factlength+offset] mov si,factorial+offset-1 add si,cx ;; for FACTLENGTH bytes std ;; Read BACKWARDS. preloop: lodsb and al,al jnz startshow dec cx jmp preloop showloop: lodsb ;; Get the digit startshow: add al,48 ;; Add ASCII nil mov dl,al ;; to DL mov ah,2 ;; Function 2 push cx ;; Save the count push si ;; Save the pointer int 33 ;; Display pop si ;; Rescue pointer pop cx ;; Rescue count loop showloop ;; Repeat mov dx,crlf+offset ;; Finish with CRLF. mov ah,9 int 33 mov ah,76 ;; Warm boot. int 33 int 32 finished?: mov ax,di ;; Get the pointer sub ax,factorial+offset cmp ax,[factlength+offset] jz more ;; If length = old jc more ;; or length > old, continue mov [factlength+offset],ax jmp repeating ;; else next number. factorial: ;; Factorial starts here db 1 factorial2: ;; followed by many bytes. end *************************************** The program was written for NASM - a public-domain assembler obtainable from GNU. If you remove the text between the rows of stars, and save it as FACTOR.ASM you can assemble it with NASM FACTOR.ASM and then rename the finished program with RENAME FACTOR FACTOR.COM I have done this already, and put it amongst my tools: http://wehner.org/tools/factor.x It is called FACTOR instead of FACTORIAL for compatibility with early DOS - which is limited to eight letters. It is called X, because few browsers are set up to understand files of this suffix. So when you go to the above address, a menu will appear for you to choose whether to OPEN or SAVE the file. You should SAVE it and rename it FACTOR.COM The program begins with a header as a guard against "salad" on the screen. EVALUATE will evaluate a decimal command-tail such as in FACTOR 1000 to give you the number 1000 in DX. It also shows the "shift-and-add" method of making fast programs (copy DX to AX, shift AX twice left, add DX to AX and shift AX left - gives ten times in AX). This method may actually be slower on the Pentium, which has a built-in maths co-processor. However, the command-tail is read only once. REPEATING repeats from bottom to top - thus, for 5!, the 1 that is already there is multiplied by 2. Then the system cycles to REPEATING to multiply by 3, and so on. Numbers up to 65535 are permitted. MULTIPLYLOOP begins at the lowest figure of the factorial (at the low end of memory), and multiplies successive figures as it heads up the memory. It is only permitted to leave this loop when the factorial is larger than it was at the last REPEATING. If it exceeds STRINGLENGTH (nominally 64800 places of decimal), it finishes with a STRING OVERFLOW error halt. Type FACTOR 364 361 at the DOS prompt, and it should reply with (carriage-return, line-feed) 17267274024 (carriage-return, line-feed). Type FACTOR 364 361>DESCEND and you should find a file known at DESCEND has been created, containing (carriage-return, line-feed) 17267274024 (carriage-return, line-feed). To get the parameters INTO the program from Qbasic, you need to use the SHELL command: a=364 b=361 SHELL "FACTOR "; a; " "; b; ">DESCEND" How you control a DOS program from other systems depends on the individual case. Only the reference manuals can help you there. ANYBODY WHO WANTS THIS TINY PROGRAM IS FREE TO FETCH IT FROM MY SITE. The copyright sign is there to warn cheats not to claim that it is THEIR work. For this particular program there is however no fee. THIS PAGE CONTAINS THE ONLY INSTRUCTIONS. Also at http://wehner.org/tools/factor.txt Charles Douglas Wehner