News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Factorial Program

Started by herge, October 06, 2008, 01:27:50 PM

Previous topic - Next topic

herge


Hi All;

Here is a Factorial Program.
It only works to 12!
Also needs a 64 bit to Ascii routine to
convert DX:AX to String.


; FACT.ASM Sunday, October 05, 2008 4:24 PM 
  include \masm32\include\masm32rt.inc
.data
public crlf
crlf db 13,10,0
.code
Start:
  call main
  inkey
  exit
  ret
main proc
    LOCAL N:DWORD
    LOCAL A:DWORD
    LOCAL buffer[20]:byte
    LOCAL buf:DWORD
    mov N, sval(input(" Factorial of " ))
    print chr$(32)
    mov  eax, N
    mov  A, eax 
    mov  ebx, eax
    and  eax, eax
    jz   loopErr
    js   loopNeg
    mov buf, ptr$(buffer)
    invoke crt__ultoa, N, buf, 10
    print buf, 32
begin:
    print chr$('*')
    mov ebx, N
    cmp ebx, 1
    jz  loopExit
    mov eax, N
    dec ebx
    mov N, ebx
    mov buf, ptr$(buffer)
    invoke crt__ultoa, N, buf, 10
    print buf, 32
    mov edx, 0
    mov eax, A
    mul ebx
    jc  overflow
    mov A, eax
    cmp ebx, 1
    jz  loopExit
    mov buf, ptr$(buffer)
    invoke crt__ultoa, A, buf, 10
    print chr$('=')
    print buf, 32
    cmp ebx, 2
    jz  loopExit
    jmp begin
loopNeg:
    print "Negative", 13 , 10, 7
    jmp X
loopErr:
    print "Zero is Invalid", 13, 10, 7
    jmp X   
overflow:
    print " Overflow has occured", 13, 10
loopExit:
X:
    mov eax, A
    and eax, eax
    jz @F
    cmp eax,3
    jnc @F
    mov buf, ptr$(buffer)
    invoke crt__ultoa, A, buf, 10
    print chr$('=')
    print buf
  @@:
    print chr$(13, 10)
    inkey
    exit       
main endp
end Start



Regards herge
// Herge born  Brussels, Belgium May 22, 1907
// Died March 3, 1983
// Cartoonist of Tintin and Snowy

MichaelW

QuoteAlso needs a 64 bit to Ascii routine to convert DX:AX to String.

I assume you mean EDX:EAX. You should be able to use _i64toa to do the conversion, but considering that you are displaying the string on the console, it would be easier to use printf to do both.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      fact dq 0
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

;-------------------------------------------------------------
; This proc uses the FPU to calculate the factorial, allowing
; it to handle 20! with a minimal number of instructions.
; Returns the factorial at the top of the FPU stack (in ST).
;-------------------------------------------------------------

factorial proc num:DWORD

    fld1                    ; ST = 1
    mov eax, 1
    .WHILE eax <= num
      push eax              ; Put EAX on the (program) stack
      fild DWORD PTR [esp]  ; Load the value just pushed into ST
                            ; Running product now in ST(1)
      pop eax               ; Remove eax from the {program) stack
      fmul                  ; ST = ST(1) * ST, ST(1)-ST(7) now empty
      inc eax
    .ENDW
    ret

factorial endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    mov esi, 1
    .WHILE esi <= 20
      invoke factorial, esi

      fistp fact            ; Store the value in ST to fact as a 64-bit
                            ; integer, all FPU registers now empty.

      invoke crt_printf, chr$("%d",9,"%I64d%c"), esi, fact, 10

      inc esi
    .ENDW

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

eschew obfuscation

herge


Hi MichaelW:

Your method is lot shorter than mine!
Yes i did mean EDX:EAX

Isn't redirection wonderful!

filename > temp.txt


Press any key to exit...
1 1
2 2
3 6
4 24
5 120
6 720
7 5040
8 40320
9 362880
10 3628800
11 39916800
12 479001600
13 6227020800
14 87178291200
15 1307674368000
16 20922789888000
17 355687428096000
18 6402373705728000
19 121645100408832000
20 2432902008176640000


Regards herge
// Herge born  Brussels, Belgium May 22, 1907
// Died March 3, 1983
// Cartoonist of Tintin and Snowy

herge

 
Hi MichaelW:

The sample c program is missing include string.h
Does strlen need it?


#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#include <conio.h>


int _tmain(int argc, _TCHAR* argv[])
{
  char buffer[65];
   int r;
   for( r=10; r>=2; --r )
   {
     _itoa( -1, buffer, r );
     printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
   }
   printf( "\n" );
   for( r=10; r>=2; --r )
   {
     _i64toa( -1L, buffer, r );
     printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
   }
   printf( "\n" );
   for( r=10; r>=2; --r )
   {
     _ui64toa( 0xffffffffffffffffL, buffer, r );
     printf( "base %d: %s (%d chars)\n", r, buffer, strlen(buffer) );
   }
   _getche( );
   return 0;
}



Regards herge
// Herge born  Brussels, Belgium May 22, 1907
// Died March 3, 1983
// Cartoonist of Tintin and Snowy

MichaelW

I'm not sure what you are doing or how you are compiling, but I think the likely answer is that string.h is necessary. Why not just bypass the problem by converting the source over to a MASM32 project.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      i64     dq -1
      u64     dq 0ffffffffffffffffh
      buffer  db 65 dup(0)
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    mov ebx, 10
    .WHILE ebx > 1
      invoke crt__itoa, -1, ADDR buffer, ebx
      invoke crt_printf, chr$("base %d: %s (%d chars)%c"), ebx,
                         ADDR buffer, len(ADDR buffer), 10
      dec ebx
    .ENDW
    print chr$(13,10)

    mov ebx, 10
    .WHILE ebx > 1
      ;--------------------------------------------------------------
      ; The _i64toa function expects the value to be a 64-bit signed
      ; integer passed on the stack. Since invoke knows how to pass
      ; 64-bit values on the stack, we can just pass the value in a
      ; QWORD variable.
      ;--------------------------------------------------------------
      invoke crt__i64toa, i64, ADDR buffer, ebx
      invoke crt_printf, chr$("base %d: %s (%d chars)%c"), ebx,
                         ADDR buffer, len(ADDR buffer), 10
      dec ebx
    .ENDW
    print chr$(13,10)

    mov ebx, 10
    .WHILE ebx > 1
      invoke crt__ui64toa, u64, ADDR buffer, ebx
      invoke crt_printf, chr$("base %d: %s (%d chars)%c"), ebx,
                         ADDR buffer, len(ADDR buffer), 10
      dec ebx
    .ENDW
    print chr$(13,10)

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


BTW, this is the code that invoke generated:

00401050 53                     push    ebx
00401051 6810304000             push    403010h
00401056 FF3504304000           push    dword ptr [403004h]
0040105C FF3500304000           push    dword ptr [403000h]
00401062 FF1518204000           call    dword ptr [_i64toa]
00401068 83C410                 add     esp,10h



eschew obfuscation

herge

 Hi MichaelW:


invoke crt_printf, chr$("%3d!= ","%I64d%c"), esi, fact, 10



Press any key to exit...
  1!= 1
  2!= 2
  3!= 6
  4!= 24
  5!= 120
  6!= 720
  7!= 5040
  8!= 40320
  9!= 362880
10!= 3628800
11!= 39916800
12!= 479001600
13!= 6227020800
14!= 87178291200
15!= 1307674368000
16!= 20922789888000
17!= 355687428096000
18!= 6402373705728000
19!= 121645100408832000
20!= 2432902008176640000


Regards herge
// Herge born  Brussels, Belgium May 22, 1907
// Died March 3, 1983
// Cartoonist of Tintin and Snowy