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.

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.

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