Author Topic: factorial of decimal number...  (Read 253 times)

0 Members and 1 Guest are viewing this topic.

ribarm

  • Gator
  • Posts: 3285
  • Marko Ribar, architect
factorial of decimal number...
« on: April 23, 2024, 08:42:24 AM »
I've read on Wikipedia about gamma function and factorial, double factorial and so on... but I am not convinced that those things written are 100% correct, so I decided to post this my sub function based on usual factorial of whole number...
Further more I am not convinced that factorial of 0 is defined as 1 - simply I'd give it nil value...
Now to present my sub :

Code: [Select]
(defun _dec_factorial ( n / _factorial )

  (defun _factorial ( n / k f r )
    (if (> n 0)
      (progn
        (setq k 0 r 1)
        (while (and (not f) (setq k (1+ k)))
          (if (= k n)
            (setq f t)
          )
          (setq r (* r k))
        )
      )
    )
    r
  )

  (if (equal n (fix n))
    (_factorial (fix n))
    (if (< 0 n 1)
      n
      (* n (_factorial (fix n)))
    )
  )
)

Any thougths...
Am I wrong or right?

Regards, M.R.
« Last Edit: April 23, 2024, 08:52:14 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

JohnK

  • Administrator
  • Seagull
  • Posts: 10652
Re: factorial of decimal number...
« Reply #1 on: April 23, 2024, 09:32:40 AM »
NOTE: I haven't read up on the concept, but I noticed a difference from yours and the windows calculator.
Example: if I type 6.2! in the basic windows calculator I get: 1,050.31
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

ribarm

  • Gator
  • Posts: 3285
  • Marko Ribar, architect
Re: factorial of decimal number...
« Reply #2 on: April 23, 2024, 09:45:09 AM »
NOTE: I haven't read up on the concept, but I noticed a difference from yours and the windows calculator.
Example: if I type 6.2! in the basic windows calculator I get: 1,050.31

Yes, there is difference, but whom shell I/we trust?
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

JohnK

  • Administrator
  • Seagull
  • Posts: 10652
Re: factorial of decimal number...
« Reply #3 on: April 23, 2024, 09:59:33 AM »
NOTE: I haven't read up on the concept, but I noticed a difference from yours and the windows calculator.
Example: if I type 6.2! in the basic windows calculator I get: 1,050.31

Yes, there is difference, but whom shell I/we trust?

wait! what? ...the calculator program shipped with windows was vetted by professionals probably many times, so I guess to be brutal, I'd trust that program over one of us lispers. Do you have a link or a concept (interest peaked)?
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

kirby

  • Newt
  • Posts: 132
Re: factorial of decimal number...
« Reply #4 on: April 23, 2024, 02:32:31 PM »
6.2! = 1050.318 according to Excel using the built in gamma function (not that Excel is the paragon of mathematical or statistical accuracy, also noting that Excel FACT() function is only for integers)

n! = n * (n-1)!
Gamma(n) = (n-1)!
therefore n! = n*Gamma(n)  (checked using Excel GAMMA function)

If you need to roll your own, check out an algorithm library and convert.
e.g. Cephes Math Library
Code - HTML5: [Select]
  1. https://www.alglib.net/specialfunctions/
  2. https://www.alglib.net/specialfunctions/gamma.php
(I use the older VB6 / VBA library when converting to AutoLisp. mainly because I'm also checking the math using Excel where the VBA code can be used almost directly)

Warning, Gamma functions get ugly real quick...
Code - vb.net: [Select]
  1. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2. ' http://www.alglib.net/
  3. 'Cephes Math Library Release 2.8:  June, 2000
  4. 'Copyright by Stephen L. Moshier
  5. '
  6. 'Contributors:
  7. '    * Sergey Bochkanov (ALGLIB project). Translation from C to
  8. '      pseudocode.
  9. '
  10. 'See subroutines comments for additional copyrights.
  11. '
  12. '>>> SOURCE LICENSE >>>
  13. 'This program is free software; you can redistribute it and/or modify
  14. 'it under the terms of the GNU General Public License as published by
  15. 'the Free Software Foundation (www.fsf.org); either version 2 of the
  16. 'License, or (at your option) any later version.
  17. '
  18. 'This program is distributed in the hope that it will be useful,
  19. 'but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. 'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. 'GNU General Public License for more details.
  22. '
  23. 'A copy of the GNU General Public License is available at
  24. 'http://www.fsf.org/licensing/licenses
  25. '
  26. '>>> END OF LICENSE >>>
  27. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  28. 'Routines
  29. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  30. 'Gamma function
  31. '
  32. 'Input parameters:
  33. '    X   -   argument
  34. '
  35. 'Domain:
  36. '    0 < X < 171.6
  37. '    -170 < X < 0, X is not an integer.
  38. '
  39. 'Relative error:
  40. ' arithmetic   domain     # trials      peak         rms
  41. '    IEEE    -170,-33      20000       2.3e-15     3.3e-16
  42. '    IEEE     -33,  33     20000       9.4e-16     2.2e-16
  43. '    IEEE      33, 171.6   20000       2.3e-15     3.2e-16
  44. '
  45. 'Cephes Math Library Release 2.8:  June, 2000
  46. 'Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
  47. 'Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007).
  48. '
  49. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  50. Public Function Gamma(ByVal X As Double) As Double
  51.     Dim Result As Double
  52.     Dim p As Double
  53.     Dim PP As Double
  54.     Dim q As Double
  55.     Dim QQ As Double
  56.     Dim z As Double
  57.     Dim i As Long
  58.     Dim SgnGam As Double
  59.  
  60.     SgnGam = 1#
  61.     q = Abs(X)
  62.     If q > 33# Then
  63.         If X < 0# Then
  64.             p = Int(q)
  65.             i = Round(p)
  66.             If i Mod 2# = 0# Then
  67.                 SgnGam = -1#
  68.             End If
  69.             z = q - p
  70.             If z > 0.5 Then
  71.                 p = p + 1#
  72.                 z = q - p
  73.             End If
  74.             z = q * sIn(Pi * z)
  75.             z = Abs(z)
  76.             z = Pi / (z * GammaStirF(q))
  77.         Else
  78.             z = GammaStirF(X)
  79.         End If
  80.         Result = SgnGam * z
  81.         Gamma = Result
  82.         Exit Function
  83.     End If
  84.     z = 1#
  85.     Do While X >= 3#
  86.         X = X - 1#
  87.         z = z * X
  88.     Loop
  89.     Do While X < 0#
  90.         If X > -0.000000001 Then
  91.             Result = z / ((1# + 0.577215664901533 * X) * X)
  92.             Gamma = Result
  93.             Exit Function
  94.         End If
  95.         z = z / X
  96.         X = X + 1#
  97.     Loop
  98.     Do While X < 2#
  99.         If X < 0.000000001 Then
  100.             Result = z / ((1# + 0.577215664901533 * X) * X)
  101.             Gamma = Result
  102.             Exit Function
  103.         End If
  104.         z = z / X
  105.         X = X + 1#
  106.     Loop
  107.     If X = 2# Then
  108.         Result = z
  109.         Gamma = Result
  110.         Exit Function
  111.     End If
  112.     X = X - 2#
  113.     PP = 1.60119522476752E-04
  114.     PP = 1.19135147006586E-03 + X * PP
  115.     PP = 1.04213797561762E-02 + X * PP
  116.     PP = 4.76367800457137E-02 + X * PP
  117.     PP = 0.207448227648436 + X * PP
  118.     PP = 0.494214826801497 + X * PP
  119.     PP = 1# + X * PP
  120.     QQ = -2.3158187332412E-05
  121.     QQ = 5.39605580493303E-04 + X * QQ
  122.     QQ = -4.45641913851797E-03 + X * QQ
  123.     QQ = 0.011813978522206 + X * QQ
  124.     QQ = 3.58236398605499E-02 + X * QQ
  125.     QQ = -0.234591795718243 + X * QQ
  126.     QQ = 7.14304917030273E-02 + X * QQ
  127.     QQ = 1# + X * QQ
  128.     Result = z * PP / QQ
  129.     Gamma = Result
  130.     Exit Function
  131.  
  132.     Gamma = Result
  133. End Function
  134.  
  135.  
  136. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  137. 'Natural logarithm of gamma function
  138. '
  139. 'Input parameters:
  140. '    X       -   argument
  141. '
  142. 'Result:
  143. '    logarithm of the absolute value of the Gamma(X).
  144. '
  145. 'Output parameters:
  146. '    SgnGam  -   sign(Gamma(X))
  147. '
  148. 'Domain:
  149. '    0 < X < 2.55e305
  150. '    -2.55e305 < X < 0, X is not an integer.
  151. '
  152. 'ACCURACY:
  153. 'arithmetic      domain        # trials     peak         rms
  154. '   IEEE    0, 3                 28000     5.4e-16     1.1e-16
  155. '   IEEE    2.718, 2.556e305     40000     3.5e-16     8.3e-17
  156. 'The error criterion was relative when the function magnitude
  157. 'was greater than one but absolute when it was less than one.
  158. '
  159. 'The following test used the relative error criterion, though
  160. 'at certain points the relative error could be much higher than
  161. 'indicated.
  162. '   IEEE    -200, -4             10000     4.8e-16     1.3e-16
  163. '
  164. 'Cephes Math Library Release 2.8:  June, 2000
  165. 'Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
  166. 'Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007).
  167. '
  168. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  169. Public Function LnGamma(ByVal X As Double, ByRef SgnGam As Double) As Double
  170.     Dim Result As Double
  171.     Dim A As Double
  172.     Dim B As Double
  173.     Dim C As Double
  174.     Dim p As Double
  175.     Dim q As Double
  176.     Dim u As Double
  177.     Dim w As Double
  178.     Dim z As Double
  179.     Dim i As Long
  180.     Dim LogPi As Double
  181.     Dim LS2PI As Double
  182.     Dim Tmp As Double
  183.  
  184.     SgnGam = 1#
  185.     LogPi = 1.1447298858494
  186.     LS2PI = 0.918938533204673
  187.     If X < -34# Then
  188.         q = -X
  189.         w = LnGamma(q, Tmp)
  190.         p = Int(q)
  191.         i = Round(p)
  192.         If i Mod 2# = 0# Then
  193.             SgnGam = -1#
  194.         Else
  195.             SgnGam = 1#
  196.         End If
  197.         z = q - p
  198.         If z > 0.5 Then
  199.             p = p + 1#
  200.             z = p - q
  201.         End If
  202.         z = q * sIn(Pi * z)
  203.         Result = LogPi - Log(z) - w
  204.         LnGamma = Result
  205.         Exit Function
  206.     End If
  207.     If X < 13# Then
  208.         z = 1#
  209.         p = 0#
  210.         u = X
  211.         Do While u >= 3#
  212.             p = p - 1#
  213.             u = X + p
  214.             z = z * u
  215.         Loop
  216.         Do While u < 2#
  217.             z = z / u
  218.             p = p + 1#
  219.             u = X + p
  220.         Loop
  221.         If z < 0# Then
  222.             SgnGam = -1#
  223.             z = -z
  224.         Else
  225.             SgnGam = 1#
  226.         End If
  227.         If u = 2# Then
  228.             Result = Log(z)
  229.             LnGamma = Result
  230.             Exit Function
  231.         End If
  232.         p = p - 2#
  233.         X = X + p
  234.         B = -1378.25152569121
  235.         B = -38801.6315134638 + X * B
  236.         B = -331612.992738871 + X * B
  237.         B = -1162370.97492762 + X * B
  238.         B = -1721737.0082084 + X * B
  239.         B = -853555.664245765 + X * B
  240.         C = 1#
  241.         C = -351.815701436523 + X * C
  242.         C = -17064.2106651881 + X * C
  243.         C = -220528.590553854 + X * C
  244.         C = -1139334.44367983 + X * C
  245.         C = -2532523.07177583 + X * C
  246.         C = -2018891.41433533 + X * C
  247.         p = X * B / C
  248.         Result = Log(z) + p
  249.         LnGamma = Result
  250.         Exit Function
  251.     End If
  252.     q = (X - 0.5) * Log(X) - X + LS2PI
  253.     If X > 100000000# Then
  254.         Result = q
  255.         LnGamma = Result
  256.         Exit Function
  257.     End If
  258.     p = 1# / (X * X)
  259.     If X >= 1000# Then
  260.         q = q + ((7.93650793650794 * 0.0001 * p - 2.77777777777778 * 0.001) * p + 8.33333333333333E-02) / X
  261.     Else
  262.         A = 8.11614167470508 * 0.0001
  263.         A = -(5.95061904284301 * 0.0001) + p * A
  264.         A = 7.93650340457717 * 0.0001 + p * A
  265.         A = -(2.777777777301 * 0.001) + p * A
  266.         A = 8.33333333333332 * 0.01 + p * A
  267.         q = q + A / X
  268.     End If
  269.     Result = q
  270.  
  271.     LnGamma = Result
  272. End Function
  273.  
  274.  
  275. Private Function GammaStirF(ByVal X As Double) As Double
  276.     Dim Result As Double
  277.     Dim y As Double
  278.     Dim w As Double
  279.     Dim v As Double
  280.     Dim Stir As Double
  281.  
  282.     w = 1# / X
  283.     Stir = 7.87311395793094E-04
  284.     Stir = -2.29549961613378E-04 + w * Stir
  285.     Stir = -2.68132617805781E-03 + w * Stir
  286.     Stir = 3.47222221605459E-03 + w * Stir
  287.     Stir = 8.33333333333482E-02 + w * Stir
  288.     w = 1# + w * Stir
  289.     y = Exp(X)
  290.     If X > 143.01608 Then
  291.         v = X ^ (0.5 * X - 0.25)
  292.         y = v * (v / y)
  293.     Else
  294.         y = X ^ ((X - 0.5) / y)
  295.     End If
  296.     Result = 2.506628274631 * y * w
  297.  
  298.     GammaStirF = Result
  299. End Function
  300.  
  301.  
  302.  
  303.  
  304.  
  305. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  306. ' http://www.alglib.net/
  307. 'Cephes Math Library Release 2.8:  June, 2000
  308. 'Copyright by Stephen L. Moshier
  309. '
  310. 'Contributors:
  311. '    * Sergey Bochkanov (ALGLIB project). Translation from C to
  312. '      pseudocode.
  313. '
  314. 'See subroutines comments for additional copyrights.
  315. '
  316. '>>> SOURCE LICENSE >>>
  317. 'This program is free software; you can redistribute it and/or modify
  318. 'it under the terms of the GNU General Public License as published by
  319. 'the Free Software Foundation (www.fsf.org); either version 2 of the
  320. 'License, or (at your option) any later version.
  321. '
  322. 'This program is distributed in the hope that it will be useful,
  323. 'but WITHOUT ANY WARRANTY; without even the implied warranty of
  324. 'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  325. 'GNU General Public License for more details.
  326. '
  327. 'A copy of the GNU General Public License is available at
  328. 'http://www.fsf.org/licensing/licenses
  329. '
  330. '>>> END OF LICENSE >>>
  331. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  332. 'Routines
  333. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  334. 'Lower Incomplete gamma integral
  335. '
  336. 'The function is defined by
  337. '
  338. '                          x
  339. '                           -
  340. '                  1       | |  -t  a-1
  341. ' igam(a,x)  =   -----     |   e   t   dt.
  342. '                 -      | |
  343. '                | (a)    -
  344. '                          0
  345. '
  346. '
  347. 'In this implementation both arguments must be positive.
  348. 'The integral is evaluated by either a power series or
  349. 'continued fraction expansion, depending on the relative
  350. 'values of a and x.
  351. '
  352. 'ACCURACY:
  353. '
  354. '                     Relative error:
  355. 'arithmetic   domain     # trials      peak         rms
  356. '   IEEE      0,30       200000       3.6e-14     2.9e-15
  357. '   IEEE      0,100      300000       9.9e-14     1.5e-14
  358. '
  359. 'Cephes Math Library Release 2.8:  June, 2000
  360. 'Copyright 1985, 1987, 2000 by Stephen L. Moshier
  361. '
  362. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  363. Public Function IncompleteGamma(ByVal A As Double, ByVal X As Double) As Double
  364.     Dim Result As Double
  365.     Dim IGammaEpsilon As Double
  366.     Dim ans As Double
  367.     Dim ax As Double
  368.     Dim C As Double
  369.     Dim r As Double
  370.     Dim Tmp As Double
  371.  
  372.     IGammaEpsilon = 0.000000000000001
  373.     If X <= 0# Or A <= 0# Then
  374.         Result = 0#
  375.         IncompleteGamma = Result
  376.         Exit Function
  377.     End If
  378.     If X > 1# And X > A Then
  379.         Result = 1# - IncompleteGammaC(A, X)
  380.         IncompleteGamma = Result
  381.         Exit Function
  382.     End If
  383.     ax = A * Log(X) - X - LnGamma(A, Tmp)
  384.     If ax < -709.782712893384 Then
  385.         Result = 0#
  386.         IncompleteGamma = Result
  387.         Exit Function
  388.     End If
  389.     ax = Exp(ax)
  390.     r = A
  391.     C = 1#
  392.     ans = 1#
  393.     Do
  394.         r = r + 1#
  395.         C = C * X / r
  396.         ans = ans + C
  397.     Loop Until C / ans <= IGammaEpsilon
  398.     Result = ans * ax / A
  399.  
  400.     IncompleteGamma = Result
  401. End Function
  402.  
  403.  
  404. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  405. 'Upper / Complemented incomplete gamma integral
  406. '
  407. 'The function is defined by
  408. '
  409. '
  410. ' igamc(a,x)   =   1 - igam(a,x)
  411. '
  412. '                           inf.
  413. '                             -
  414. '                    1       | |  -t  a-1
  415. '              =   -----     |   e   t   dt.
  416. '                   -      | |
  417. '                  | (a)    -
  418. '                            x
  419. '
  420. '
  421. 'In this implementation both arguments must be positive.
  422. 'The integral is evaluated by either a power series or
  423. 'continued fraction expansion, depending on the relative
  424. 'values of a and x.
  425. '
  426. 'ACCURACY:
  427. '
  428. 'Tested at random a, x.
  429. '               a         x                      Relative error:
  430. 'arithmetic   domain   domain     # trials      peak         rms
  431. '   IEEE     0.5,100   0,100      200000       1.9e-14     1.7e-15
  432. '   IEEE     0.01,0.5  0,100      200000       1.4e-13     1.6e-15
  433. '
  434. 'Cephes Math Library Release 2.8:  June, 2000
  435. 'Copyright 1985, 1987, 2000 by Stephen L. Moshier
  436. '
  437. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  438. Public Function IncompleteGammaC(ByVal A As Double, _
  439.          ByVal X As Double) As Double
  440.     Dim Result As Double
  441.     Dim IGammaEpsilon As Double
  442.     Dim IGammaBigNumber As Double
  443.     Dim IGammaBigNumberInv As Double
  444.     Dim ans As Double
  445.     Dim ax As Double
  446.     Dim C As Double
  447.     Dim yc As Double
  448.     Dim r As Double
  449.     Dim t As Double
  450.     Dim y As Double
  451.     Dim z As Double
  452.     Dim pk As Double
  453.     Dim pkm1 As Double
  454.     Dim pkm2 As Double
  455.     Dim qk As Double
  456.     Dim qkm1 As Double
  457.     Dim qkm2 As Double
  458.     Dim Tmp As Double
  459.  
  460.     IGammaEpsilon = 0.000000000000001
  461.     IGammaBigNumber = 4.5035996273705E+15
  462.     IGammaBigNumberInv = 2.22044604925031 * 1E-16
  463.     If X <= 0# Or A <= 0# Then
  464.         Result = 1#
  465.         IncompleteGammaC = Result
  466.         Exit Function
  467.     End If
  468.     If X < 1# Or X < A Then
  469.         Result = 1# - IncompleteGamma(A, X)
  470.         IncompleteGammaC = Result
  471.         Exit Function
  472.     End If
  473.     ax = A * Log(X) - X - LnGamma(A, Tmp)
  474.     If ax < -709.782712893384 Then
  475.         Result = 0#
  476.         IncompleteGammaC = Result
  477.         Exit Function
  478.     End If
  479.     ax = Exp(ax)
  480.     y = 1# - A
  481.     z = X + y + 1#
  482.     C = 0#
  483.     pkm2 = 1#
  484.     qkm2 = X
  485.     pkm1 = X + 1#
  486.     qkm1 = z * X
  487.     ans = pkm1 / qkm1
  488.     Do
  489.         C = C + 1#
  490.         y = y + 1#
  491.         z = z + 2#
  492.         yc = y * C
  493.         pk = pkm1 * z - pkm2 * yc
  494.         qk = qkm1 * z - qkm2 * yc
  495.         If qk <> 0# Then
  496.             r = pk / qk
  497.             t = Abs((ans - r) / r)
  498.             ans = r
  499.         Else
  500.             t = 1#
  501.         End If
  502.         pkm2 = pkm1
  503.         pkm1 = pk
  504.         qkm2 = qkm1
  505.         qkm1 = qk
  506.         If Abs(pk) > IGammaBigNumber Then
  507.             pkm2 = pkm2 * IGammaBigNumberInv
  508.             pkm1 = pkm1 * IGammaBigNumberInv
  509.             qkm2 = qkm2 * IGammaBigNumberInv
  510.             qkm1 = qkm1 * IGammaBigNumberInv
  511.         End If
  512.     Loop Until t <= IGammaEpsilon
  513.     Result = ans * ax
  514.  
  515.     IncompleteGammaC = Result
  516. End Function
  517.  
  518.  
  519. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  520. 'Inverse of complemented imcomplete gamma integral
  521. '
  522. 'Given p, the function finds x such that
  523. '
  524. ' igamc( a, x ) = p.
  525. '
  526. 'Starting with the approximate value
  527. '
  528. '        3
  529. ' x = a t
  530. '
  531. ' where
  532. '
  533. ' t = 1 - d - ndtri(p) sqrt(d)
  534. '
  535. 'and
  536. '
  537. ' d = 1/9a,
  538. '
  539. 'the routine performs up to 10 Newton iterations to find the
  540. 'root of igamc(a,x) - p = 0.
  541. '
  542. 'ACCURACY:
  543. '
  544. 'Tested at random a, p in the intervals indicated.
  545. '
  546. '               a        p                      Relative error:
  547. 'arithmetic   domain   domain     # trials      peak         rms
  548. '   IEEE     0.5,100   0,0.5       100000       1.0e-14     1.7e-15
  549. '   IEEE     0.01,0.5  0,0.5       100000       9.0e-14     3.4e-15
  550. '   IEEE    0.5,10000  0,0.5        20000       2.3e-13     3.8e-14
  551. '
  552. 'Cephes Math Library Release 2.8:  June, 2000
  553. 'Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
  554. '
  555. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  556. Public Function InvIncompleteGammaC(ByVal A As Double, _
  557.          ByVal y0 As Double) As Double
  558.     Dim Result As Double
  559.     Dim IGammaEpsilon As Double
  560.     Dim IInvGammaBigNumber As Double
  561.     Dim x0 As Double
  562.     Dim x1 As Double
  563.     Dim X As Double
  564.     Dim yl As Double
  565.     Dim yh As Double
  566.     Dim y As Double
  567.     Dim d As Double
  568.     Dim lgm As Double
  569.     Dim dithresh As Double
  570.     Dim i As Long
  571.     Dim dir As Long
  572.     Dim Tmp As Double
  573.  
  574.     IGammaEpsilon = 0.000000000000001
  575.     IInvGammaBigNumber = 4.5035996273705E+15
  576.     x0 = IInvGammaBigNumber
  577.     yl = 0#
  578.     x1 = 0#
  579.     yh = 1#
  580.     dithresh = 5# * IGammaEpsilon
  581.     d = 1# / (9# * A)
  582.     y = 1# - d - InvNormalDistribution(y0) * Sqr(d)
  583.     X = A * y * y * y
  584.     lgm = LnGamma(A, Tmp)
  585.     i = 0#
  586.     Do While i < 10#
  587.         If X > x0 Or X < x1 Then
  588.             d = 0.0625
  589.             Exit Do
  590.         End If
  591.         y = IncompleteGammaC(A, X)
  592.         If y < yl Or y > yh Then
  593.             d = 0.0625
  594.             Exit Do
  595.         End If
  596.         If y < y0 Then
  597.             x0 = X
  598.             yl = y
  599.         Else
  600.             x1 = X
  601.             yh = y
  602.         End If
  603.         d = (A - 1#) * Log(X) - X - lgm
  604.         If d < -709.782712893384 Then
  605.             d = 0.0625
  606.             Exit Do
  607.         End If
  608.         d = -Exp(d)
  609.         d = (y - y0) / d
  610.         If Abs(d / X) < IGammaEpsilon Then
  611.             Result = X
  612.             InvIncompleteGammaC = Result
  613.             Exit Function
  614.         End If
  615.         X = X - d
  616.         i = i + 1#
  617.     Loop
  618.     If x0 = IInvGammaBigNumber Then
  619.         If X <= 0# Then
  620.             X = 1#
  621.         End If
  622.         Do While x0 = IInvGammaBigNumber
  623.             X = (1# + d) * X
  624.             y = IncompleteGammaC(A, X)
  625.             If y < y0 Then
  626.                 x0 = X
  627.                 yl = y
  628.                 Exit Do
  629.             End If
  630.             d = d + d
  631.         Loop
  632.     End If
  633.     d = 0.5
  634.     dir = 0#
  635.     i = 0#
  636.     Do While i < 400#
  637.         X = x1 + d * (x0 - x1)
  638.         y = IncompleteGammaC(A, X)
  639.         lgm = (x0 - x1) / (x1 + x0)
  640.         If Abs(lgm) < dithresh Then
  641.             Exit Do
  642.         End If
  643.         lgm = (y - y0) / y0
  644.         If Abs(lgm) < dithresh Then
  645.             Exit Do
  646.         End If
  647.         If X <= 0# Then
  648.             Exit Do
  649.         End If
  650.         If y >= y0 Then
  651.             x1 = X
  652.             yh = y
  653.             If dir < 0# Then
  654.                 dir = 0#
  655.                 d = 0.5
  656.             Else
  657.                 If dir > 1# Then
  658.                     d = 0.5 * d + 0.5
  659.                 Else
  660.                     d = (y0 - yl) / (yh - yl)
  661.                 End If
  662.             End If
  663.             dir = dir + 1#
  664.         Else
  665.             x0 = X
  666.             yl = y
  667.             If dir > 0# Then
  668.                 dir = 0#
  669.                 d = 0.5
  670.             Else
  671.                 If dir < -1# Then
  672.                     d = 0.5 * d
  673.                 Else
  674.                     d = (y0 - yl) / (yh - yl)
  675.                 End If
  676.             End If
  677.             dir = dir - 1#
  678.         End If
  679.         i = i + 1#
  680.     Loop
  681.     Result = X
  682.  
  683.     InvIncompleteGammaC = Result
  684. End Function
  685.  

kirby

  • Newt
  • Posts: 132
Re: factorial of decimal number...
« Reply #5 on: April 23, 2024, 02:46:34 PM »
Another reference, the Numerical Recipes books.  Lots of great tips and gotcha's in the text.
'Obsolete' Version 2 is available to read online
I like the Fortran version because I'm a Civil engineer and old

Gamma function (lnGamma using Stirling approximation) and decimal factorial function:
Code - HTML5: [Select]
  1. https://s3.amazonaws.com/nrbook.com/book_F210.html

ribarm

  • Gator
  • Posts: 3285
  • Marko Ribar, architect
Re: factorial of decimal number...
« Reply #6 on: April 23, 2024, 03:19:56 PM »
I've changed my function and now I have better results... It's more like calculator, but it is also not exact match...

Code: [Select]
(defun _dec_factorial ( n / _factorial )

  (defun _factorial ( n / k f r )
    (if (> n 0)
      (progn
        (setq k 0 r 1)
        (while (and (not f) (setq k (1+ k)))
          (if (= k n)
            (setq f t)
          )
          (setq r (* r k))
        )
      )
    )
    r
  )

  (if (equal n (fix n))
    (_factorial (fix n))
    (if (< 0 n 1)
      n
      (+ (_factorial (fix n)) (* (- (_factorial (1+ (fix n))) (_factorial (fix n))) (- n (fix n))))
    )
  )
)

The same, but more efficient...

Code: [Select]
(defun _dec_factorial ( n / _factorial r )

  (defun _factorial ( n / k f r )
    (if (> n 0)
      (progn
        (setq k 0 r 1)
        (while (and (not f) (setq k (1+ k)))
          (if (= k n)
            (setq f t)
          )
          (setq r (* r k))
        )
      )
    )
    r
  )

  (if (equal n (fix n))
    (_factorial (fix n))
    (if (< 0 n 1)
      n
      (+ (setq r (_factorial (fix n))) (* (- (* r (1+ (fix n))) r) (- n (fix n))))
    )
  )
)

M.R.
« Last Edit: April 23, 2024, 04:18:16 PM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

kirby

  • Newt
  • Posts: 132
Re: factorial of decimal number...
« Reply #7 on: April 23, 2024, 06:42:21 PM »
Fun end of day mental exercise...

Test function matches Excel to 5 decimal places (vs. built in functions GAMMALN & GAMMA, decimal factorial computed from X*Gamma(X))
and in range of 0.1 to 10.0 in 0.1 increments
(but maybe Excel is wrong too...)

Code - Auto/Visual Lisp: [Select]
  1. (defun C:TestGamma ( / CNT MyVal LG G DF)
  2. ; Test function for 'LnGamma', 'Gamma', and 'DecimalFact'
  3. ; KJM - April 2024
  4. ; Uses custom functions
  5. ;       lngamma
  6. ;       gamma
  7. ;       decimalfact
  8.  
  9. (setq OutList nil)
  10.  
  11. (prompt "\nValue  LnGamma  Gamma  DecFact")
  12.  
  13. ; Test from 0.1 to 10.0
  14. (setq CNT 1)
  15. (repeat 100
  16.         (setq MyVal (/ (float CNT) 10.0))
  17.  
  18.         (setq LG (lngamma MyVal))
  19.         (setq G (gamma MyVal))
  20.         (setq DF (DecimalFact MyVal))
  21.  
  22.         ; Report
  23.         (prompt "\n")(princ (rtos MyVal 2 3))
  24.         (prompt "  ")(princ (rtos LG 2 5))
  25.         (prompt "  ")(princ (rtos G 2 5))
  26.         (prompt "  ")(princ (rtos DF 2 5))
  27.  
  28.         (setq OutList (cons (list MyVal LG G DF) OutList))
  29.  
  30.         (setq CNT (1+ CNT))
  31. ) ; close repeat
  32.  
  33. (prompt "\nCompleted!")
  34. )
  35.  
  36.  
  37.  
  38. (defun DecimalFact ( X /
  39.                 OutVal tol
  40.                 )
  41. ; Decimal factorial function x! = x*gamma(x)
  42. ; KJM - April 2024
  43. ; Input
  44. ;       X - (positive real)
  45. ; Returns
  46. ;       Natural logarithm of gamma function
  47. ; Uses custom functions:
  48. ;       Gamma
  49.  
  50. (setq OutVal nil)
  51.  
  52. (setq tol 1e-6)
  53.  
  54. (if (> X tol)   ; Must by positive
  55.         (setq OutVal (* X (gamma X)))
  56. ) ; close if
  57.  
  58. OutVal
  59. )
  60.  
  61.  
  62. (defun Gamma ( X /
  63.                 OutVal tol
  64.                 )
  65. ; Gamma function
  66. ; KJM - April 2024
  67. ; Input
  68. ;       X - (positive real)
  69. ; Returns
  70. ;       gamma function of X
  71. ; Uses custom functions:
  72. ;       LnGamma
  73.  
  74. (setq OutVal nil)
  75.  
  76. (setq tol 1e-6)
  77.  
  78. (if (> X tol)   ; Must by positive
  79.         (setq OutVal (exp (lngamma X)))
  80. ) ; close if
  81.  
  82. OutVal
  83. )
  84.  
  85.  
  86. (defun LnGamma ( X /
  87.         OutVal tol Coeff B A CNT
  88.         )
  89. ; Natural Log of Gamma function by Lanczos approximation
  90. ; KJM - April 2024
  91. ; Input
  92. ;       X - (positive real)
  93. ; Returns
  94. ;       Natural logarithm of gamma function of X
  95. ; Uses custom functions:
  96. ;       none!
  97.  
  98. ; See:
  99. ;       https://en.wikipedia.org/wiki/Lanczos_approximation
  100.  
  101.  
  102. (setq OutVal nil)
  103.  
  104. (setq tol 1e-6)
  105.  
  106. (if (> X tol)   ; Must by positive
  107.   (progn
  108.  
  109.         (setq Coeff (list       ; list of 7 coefficients
  110.                   1.000000000190015
  111.                  76.180091729471463
  112.                 -86.505320329416768
  113.                  24.014098240830910
  114.                  -1.231739572450155
  115.                   0.001208650973866
  116.                  -0.000005395239385
  117.         )) ; close setq list
  118.        
  119.         (if (< X 0.5)
  120.           (progn
  121.                 ; Reflection formula for small X
  122.                 (setq OutVal (-
  123.                         (log (/ pi (sin (* X pi))))
  124.                         (LnGamma (- 1.0 X))
  125.                 ))
  126.           )
  127.           (progn
  128.                 (setq X (- X 1.0))
  129.                 (setq B (+ X 5.5))
  130.                 (setq A (nth 0 Coeff))
  131.                
  132.                 (setq CNT 1)
  133.                 (repeat (1- (length Coeff))
  134.                         (setq A (+ A (/ (nth CNT Coeff) (+ X (float CNT)))))
  135.                         (setq CNT (1+ CNT))
  136.                 ) ; close repeat
  137.                
  138.                 (setq OutVal (+
  139.                         (log (sqrt (* 2.0 pi)))
  140.                         (log A)
  141.                         (* -1.0 B)
  142.                         (* (log B) (+ X 0.5))
  143.                 ))
  144.           )
  145.         ) ; close if   
  146.   )
  147. ) ; close if
  148. OutVal
  149. )
  150.