Page 1 of 1

Factoral function

Posted: Sat Dec 09, 2006 5:57 am
by PB&J Lover
I'm trying to perfect a factoral function.

Code: Select all

Procedure.q Factoral(n.l)
If n >= 0
   If n > 0
      Define answer.q = 1
        While n > 0
          answer = answer * n
          n - 1   
        Wend
        ProcedureReturn answer
   Else
        ProcedureReturn 1
   EndIf
Else   
   ProcedureReturn -1
EndIf
EndProcedure
When I use a number greater than 20 I get an incorrect result (granted it is a very large number). How can I correct this so that it gives me correct results? Is there a way to deal with very large numbers?

Thanks. :shock:

Posted: Sat Dec 09, 2006 12:10 pm
by Pupil
If i remember correctly Rings once did a big number lib, which uses strings to hold the numbers. This ofcourse comes with a penalty in speed as the calculations more or less needs to mimic the way it's done manually with pen and paper..

Maybe it's part of PBOSL now?

Posted: Sat Dec 09, 2006 4:09 pm
by Helle
For Fun:

Code: Select all

Procedure Factoral(n.l)

M = 2 * n
Dim P(2 * n) 

P(M) = 1

For I = 1 To M/2
    For F = M To 1 Step -1
       P(F) = P(F) * I
    Next F

    For F = M To 1 Step -1
       P(F-1) = P(F-1) + Int(P(F)/10)
       P(F) = P(F)-10 * Int(P(F)/10)
    Next F

    For F = 1 To M
      If P(F) = 0
         S = F
      EndIf
    
      If P(F) > 0
         F = M
      EndIf
    Next F

    For F = S + 1 To M
        Fak$ = Fak$ + Str(P(F))
    Next F

    Debug Str(I) + "!" + "   =   " + Fak$
    Fak$ = ""

Next I

EndProcedure 

Factoral(100)

Posted: Sat Dec 09, 2006 5:53 pm
by Helle
Possible a DIM-error in PB or in my head( :) ), this is correct for bigger numbers:

Code: Select all

Global Fak1$

Procedure Factoral(n)

M = 3 * n
Dim P(3 * n) 

P(M) = 1

For I = 1 To M/2
    For F = M To 1 Step -1
       P(F) = P(F) * I
    Next F

    For F = M To 1 Step -1
       P(F-1) = P(F-1) + Int(P(F)/10)
       P(F) = P(F)-10 * Int(P(F)/10)
    Next F

    For F = 1 To M
      If P(F) = 0
         S = F
      EndIf
    
      If P(F) > 0
         F = M
      EndIf
    Next F

    For F = S + 1 To M
        Fak$ = Fak$ + Str(P(F))
    Next F

    If I = n
       Fak1$=Fak$
        Break  
    EndIf 
      
    Fak$ = ""

Next I
  
EndProcedure 

Factoral(1000)
Debug Fak1$
Gruss
Helle

Posted: Sun Dec 10, 2006 8:58 pm
by PB&J Lover
This is great but what I'd like to know is, what is the largest number I could deal with in my original function. Is there a way get it do deal with larger (real) numbers and not output a string.

ps. Why did you declare a global variable and then reference it in the procedure. That's not a great practice. It is better if all the procedure variables are local and you use procedurereturn to pass the output back.

Thanks for the help though.

:D

Posted: Sun Dec 10, 2006 10:11 pm
by Froggerprogger
@helle
great snippet !!

@PB&J Lover
the biggest number of a signed quad is
(2^63)-1 = 9.223.372.036.854.775.807
Therefore your code works up to
20! = 2.432.902.008.176.640.000, because
21! = 51.090.942.171.709.440.000 > (2^63)-1

Just for fun here's a lookuptable-version:

Code: Select all

Procedure.q Fac(n.l)
  Select n
    Case  0 : ProcedureReturn 1
    Case  1 : ProcedureReturn 1  
    Case  2 : ProcedureReturn 2
    Case  3 : ProcedureReturn 6
    Case  4 : ProcedureReturn 24
    Case  5 : ProcedureReturn 120
    Case  6 : ProcedureReturn 720
    Case  7 : ProcedureReturn 5040
    Case  8 : ProcedureReturn 40320
    Case  9 : ProcedureReturn 362880
    Case 10 : ProcedureReturn 3628800
    Case 11 : ProcedureReturn 39916800
    Case 12 : ProcedureReturn 479001600
    Case 13 : ProcedureReturn 6227020800
    Case 14 : ProcedureReturn 87178291200
    Case 15 : ProcedureReturn 1307674368000
    Case 16 : ProcedureReturn 20922789888000
    Case 17 : ProcedureReturn 355687428096000
    Case 18 : ProcedureReturn 6402373705728000
    Case 19 : ProcedureReturn 121645100408832000
    Case 20 : ProcedureReturn 2432902008176640000
    Default : ProcedureReturn -1
  EndSelect
EndProcedure