@@ -3,13 +3,13 @@ import { gammaG, gammaNumber, gammaP } from '../../plain/number/index.js'
33
44const name = 'gamma'
55const dependencies = [
6- 'typed' , 'config' , 'multiplyScalar ' , 'pow' , 'bernoulli ',
7- 'BigNumber ' , 'Complex '
6+ 'typed' , 'config' , 'BigNumber ' , 'Complex ' ,
7+ 'isInteger ' , 'bernoulli' , 'equal '
88]
99
1010export const createGamma = /* #__PURE__ */ factory ( name , dependencies , ( {
11- typed, config, multiplyScalar , pow , bernoulli ,
12- BigNumber , Complex
11+ typed, config, BigNumber , Complex ,
12+ isInteger , bernoulli , equal
1313} ) => {
1414 /**
1515 * Compute the gamma function of a value using Lanczos approximation for
@@ -78,18 +78,41 @@ export const createGamma = /* #__PURE__ */ factory(name, dependencies, ({
7878 return x . mul ( twoPiSqrt ) . mul ( tpow ) . mul ( expt )
7979 }
8080
81+ const piB = BigNumber . acos ( - 1 )
82+ const halflog2piB = piB . times ( 2 ) . ln ( ) . div ( 2 )
83+ const sqrtpiB = piB . sqrt ( )
84+ const zeroB = new BigNumber ( 0 )
85+ const twoB = new BigNumber ( 2 )
86+ const neg2B = new BigNumber ( - 2 )
87+
8188 return typed ( name , {
8289 number : gammaNumber ,
8390 Complex : gammaComplex ,
8491 BigNumber : function ( n ) {
85- if ( n . isInteger ( ) ) {
92+ // Handle special values here
93+ if ( ! n . isFinite ( ) ) {
94+ return new BigNumber ( n . isNegative ( ) ? NaN : Infinity )
95+ }
96+ if ( isInteger ( n ) ) {
8697 return ( n . isNegative ( ) || n . isZero ( ) )
8798 ? new BigNumber ( Infinity )
88- : bigFactorial ( n . minus ( 1 ) )
99+ : bigFactorial ( n . round ( ) . minus ( 1 ) )
89100 }
90-
91- if ( ! n . isFinite ( ) ) {
92- return new BigNumber ( n . isNegative ( ) ? NaN : Infinity )
101+ let nhalf = n . minus ( 0.5 )
102+ if ( equal ( nhalf , zeroB ) ) return sqrtpiB
103+ if ( isInteger ( nhalf ) ) {
104+ nhalf = nhalf . round ( ) // in case there was roundoff error coming in
105+ let doubleFactorial = nhalf . abs ( ) . times ( 2 ) . minus ( 1 )
106+ // todo: replace following when factorial implementation finalized
107+ let factor = doubleFactorial . minus ( 2 )
108+ while ( factor . greaterThan ( 1 ) ) {
109+ doubleFactorial = doubleFactorial . times ( factor )
110+ factor = factor . minus ( 2 )
111+ }
112+ if ( nhalf . lessThan ( 0 ) ) {
113+ return neg2B . pow ( nhalf . abs ( ) ) . times ( sqrtpiB ) . div ( doubleFactorial )
114+ }
115+ return doubleFactorial . times ( sqrtpiB ) . div ( twoB . pow ( nhalf ) )
93116 }
94117
95118 return gammaBig ( n )
@@ -101,8 +124,6 @@ export const createGamma = /* #__PURE__ */ factory(name, dependencies, ({
101124 // but adapted to work only for real inputs.
102125 // Note for future the same core algorithm can be used for 1/gamma
103126 // or log-gamma, see details in the paper.
104- const Pi = BigNumber . acos ( - 1 )
105- const halflog2p = Pi . times ( 2 ) . ln ( ) . div ( 2 )
106127 // Our goal is to compute relTol digits of gamma
107128 let digits = Math . abs ( Math . log10 ( config . relTol ) )
108129 const bits = Math . min ( digits * 10 / 3 , 3 )
@@ -118,7 +139,7 @@ export const createGamma = /* #__PURE__ */ factory(name, dependencies, ({
118139 let inaccurate = true
119140 let mainsum = new BigNumber ( 0 )
120141 let shifted = z . plus ( r )
121- console . log ( 'Trying for' , digits , 'with shift' , r )
142+ // console.trace ('Trying for', digits, 'with shift', r)
122143 while ( inaccurate ) {
123144 const needPrec = digits + 3 + Math . floor (
124145 shifted . ln ( ) . times ( shifted ) . log ( ) . toNumber ( ) )
@@ -161,7 +182,7 @@ export const createGamma = /* #__PURE__ */ factory(name, dependencies, ({
161182 }
162183 // OK, we should have an accurate mainsum
163184 const shiftGamma = mainsum
164- . plus ( halflog2p )
185+ . plus ( halflog2piB )
165186 . minus ( shifted )
166187 . plus ( shifted . ln ( ) . times ( shifted . minus ( 0.5 ) ) )
167188 // TODO: when implementation of rising factorial settled,
@@ -174,8 +195,8 @@ export const createGamma = /* #__PURE__ */ factory(name, dependencies, ({
174195 }
175196 let gamma
176197 if ( reflect ) {
177- const angleFactor = n . mod ( 2 ) . times ( Pi ) . sin ( )
178- gamma = shiftGamma . neg ( ) . exp ( ) . times ( Pi ) . times ( rising ) . div ( angleFactor )
198+ const angleFactor = n . mod ( 2 ) . times ( piB ) . sin ( )
199+ gamma = shiftGamma . neg ( ) . exp ( ) . times ( piB ) . times ( rising ) . div ( angleFactor )
179200 } else gamma = shiftGamma . exp ( ) . div ( rising )
180201 return gamma . toDecimalPlaces ( digits )
181202 }
0 commit comments