@@ -415,6 +415,7 @@ type formulaFuncs struct {
415
415
// FALSE
416
416
// FIND
417
417
// FINDB
418
+ // FINV
418
419
// FISHER
419
420
// FISHERINV
420
421
// FIXED
@@ -5835,6 +5836,340 @@ func (fn *formulaFuncs) EXPONDIST(argsList *list.List) formulaArg {
5835
5836
return newNumberFormulaArg (lambda .Number * math .Exp (- lambda .Number * x .Number ))
5836
5837
}
5837
5838
5839
+ // d1mach returns double precision real machine constants.
5840
+ func d1mach (i int ) float64 {
5841
+ arr := []float64 {
5842
+ 2.2250738585072014e-308 ,
5843
+ 1.7976931348623158e+308 ,
5844
+ 1.1102230246251565e-16 ,
5845
+ 2.2204460492503131e-16 ,
5846
+ 0.301029995663981195 ,
5847
+ }
5848
+ if i > len (arr ) {
5849
+ return 0
5850
+ }
5851
+ return arr [i - 1 ]
5852
+ }
5853
+
5854
+ // chebyshevInit determines the number of terms for the double precision
5855
+ // orthogonal series "dos" needed to insure the error is no larger
5856
+ // than "eta". Ordinarily eta will be chosen to be one-tenth machine
5857
+ // precision.
5858
+ func chebyshevInit (nos int , eta float64 , dos []float64 ) int {
5859
+ i , e := 0 , 0.0
5860
+ if nos < 1 {
5861
+ return 0
5862
+ }
5863
+ for ii := 1 ; ii <= nos ; ii ++ {
5864
+ i = nos - ii
5865
+ e += math .Abs (dos [i ])
5866
+ if e > eta {
5867
+ return i
5868
+ }
5869
+ }
5870
+ return i
5871
+ }
5872
+
5873
+ // chebyshevEval evaluates the n-term Chebyshev series "a" at "x".
5874
+ func chebyshevEval (n int , x float64 , a []float64 ) float64 {
5875
+ if n < 1 || n > 1000 || x < - 1.1 || x > 1.1 {
5876
+ return math .NaN ()
5877
+ }
5878
+ twox , b0 , b1 , b2 := x * 2 , 0.0 , 0.0 , 0.0
5879
+ for i := 1 ; i <= n ; i ++ {
5880
+ b2 = b1
5881
+ b1 = b0
5882
+ b0 = twox * b1 - b2 + a [n - i ]
5883
+ }
5884
+ return (b0 - b2 ) * 0.5
5885
+ }
5886
+
5887
+ // lgammacor is an implementation for the log(gamma) correction.
5888
+ func lgammacor (x float64 ) float64 {
5889
+ algmcs := []float64 {
5890
+ 0.1666389480451863247205729650822 , - 0.1384948176067563840732986059135e-4 ,
5891
+ 0.9810825646924729426157171547487e-8 , - 0.1809129475572494194263306266719e-10 ,
5892
+ 0.6221098041892605227126015543416e-13 , - 0.3399615005417721944303330599666e-15 ,
5893
+ 0.2683181998482698748957538846666e-17 , - 0.2868042435334643284144622399999e-19 ,
5894
+ 0.3962837061046434803679306666666e-21 , - 0.6831888753985766870111999999999e-23 ,
5895
+ 0.1429227355942498147573333333333e-24 , - 0.3547598158101070547199999999999e-26 ,
5896
+ 0.1025680058010470912000000000000e-27 , - 0.3401102254316748799999999999999e-29 ,
5897
+ 0.1276642195630062933333333333333e-30 ,
5898
+ }
5899
+ nalgm := chebyshevInit (15 , d1mach (3 ), algmcs )
5900
+ xbig := 1.0 / math .Sqrt (d1mach (3 ))
5901
+ xmax := math .Exp (math .Min (math .Log (d1mach (2 )/ 12.0 ), - math .Log (12.0 * d1mach (1 ))))
5902
+ if x < 10.0 {
5903
+ return math .NaN ()
5904
+ } else if x >= xmax {
5905
+ return 4.930380657631324e-32
5906
+ } else if x < xbig {
5907
+ tmp := 10.0 / x
5908
+ return chebyshevEval (nalgm , tmp * tmp * 2.0 - 1.0 , algmcs ) / x
5909
+ }
5910
+ return 1.0 / (x * 12.0 )
5911
+ }
5912
+
5913
+ // logrelerr compute the relative error logarithm.
5914
+ func logrelerr (x float64 ) float64 {
5915
+ alnrcs := []float64 {
5916
+ 0.10378693562743769800686267719098e+1 , - 0.13364301504908918098766041553133 ,
5917
+ 0.19408249135520563357926199374750e-1 , - 0.30107551127535777690376537776592e-2 ,
5918
+ 0.48694614797154850090456366509137e-3 , - 0.81054881893175356066809943008622e-4 ,
5919
+ 0.13778847799559524782938251496059e-4 , - 0.23802210894358970251369992914935e-5 ,
5920
+ 0.41640416213865183476391859901989e-6 , - 0.73595828378075994984266837031998e-7 ,
5921
+ 0.13117611876241674949152294345011e-7 , - 0.23546709317742425136696092330175e-8 ,
5922
+ 0.42522773276034997775638052962567e-9 , - 0.77190894134840796826108107493300e-10 ,
5923
+ 0.14075746481359069909215356472191e-10 , - 0.25769072058024680627537078627584e-11 ,
5924
+ 0.47342406666294421849154395005938e-12 , - 0.87249012674742641745301263292675e-13 ,
5925
+ 0.16124614902740551465739833119115e-13 , - 0.29875652015665773006710792416815e-14 ,
5926
+ 0.55480701209082887983041321697279e-15 , - 0.10324619158271569595141333961932e-15 ,
5927
+ 0.19250239203049851177878503244868e-16 , - 0.35955073465265150011189707844266e-17 ,
5928
+ 0.67264542537876857892194574226773e-18 , - 0.12602624168735219252082425637546e-18 ,
5929
+ 0.23644884408606210044916158955519e-19 , - 0.44419377050807936898878389179733e-20 ,
5930
+ 0.83546594464034259016241293994666e-21 , - 0.15731559416479562574899253521066e-21 ,
5931
+ 0.29653128740247422686154369706666e-22 , - 0.55949583481815947292156013226666e-23 ,
5932
+ 0.10566354268835681048187284138666e-23 , - 0.19972483680670204548314999466666e-24 ,
5933
+ 0.37782977818839361421049855999999e-25 , - 0.71531586889081740345038165333333e-26 ,
5934
+ 0.13552488463674213646502024533333e-26 , - 0.25694673048487567430079829333333e-27 ,
5935
+ 0.48747756066216949076459519999999e-28 , - 0.92542112530849715321132373333333e-29 ,
5936
+ 0.17578597841760239233269760000000e-29 , - 0.33410026677731010351377066666666e-30 ,
5937
+ 0.63533936180236187354180266666666e-31 ,
5938
+ }
5939
+ nlnrel := chebyshevInit (43 , 0.1 * d1mach (3 ), alnrcs )
5940
+ if x <= - 1 {
5941
+ return math .NaN ()
5942
+ }
5943
+ if math .Abs (x ) <= 0.375 {
5944
+ return x * (1.0 - x * chebyshevEval (nlnrel , x / 0.375 , alnrcs ))
5945
+ }
5946
+ return math .Log (x + 1.0 )
5947
+ }
5948
+
5949
+ // logBeta is an implementation for the log of the beta distribution
5950
+ // function.
5951
+ func logBeta (a , b float64 ) float64 {
5952
+ corr , p , q := 0.0 , a , a
5953
+ if b < p {
5954
+ p = b
5955
+ }
5956
+ if b > q {
5957
+ q = b
5958
+ }
5959
+ if p < 0 {
5960
+ return math .NaN ()
5961
+ }
5962
+ if p == 0 {
5963
+ return math .MaxFloat64
5964
+ }
5965
+ if p >= 10.0 {
5966
+ corr = lgammacor (p ) + lgammacor (q ) - lgammacor (p + q )
5967
+ return math .Log (q )* - 0.5 + 0.918938533204672741780329736406 + corr + (p - 0.5 )* math .Log (p / (p + q )) + q * logrelerr (- p / (p + q ))
5968
+ }
5969
+ if q >= 10 {
5970
+ corr = lgammacor (q ) - lgammacor (p + q )
5971
+ val , _ := math .Lgamma (p )
5972
+ return val + corr + p - p * math .Log (p + q ) + (q - 0.5 )* logrelerr (- p / (p + q ))
5973
+ }
5974
+ return math .Log (math .Gamma (p ) * (math .Gamma (q ) / math .Gamma (p + q )))
5975
+ }
5976
+
5977
+ // pbetaRaw is a part of pbeta for the beta distribution.
5978
+ func pbetaRaw (alnsml , ans , eps , p , pin , q , sml , x , y float64 ) float64 {
5979
+ if q > 1.0 {
5980
+ xb := p * math .Log (y ) + q * math .Log (1.0 - y ) - logBeta (p , q ) - math .Log (q )
5981
+ ib := int (math .Max (xb / alnsml , 0.0 ))
5982
+ term := math .Exp (xb - float64 (ib )* alnsml )
5983
+ c := 1.0 / (1.0 - y )
5984
+ p1 := q * c / (p + q - 1.0 )
5985
+ finsum := 0.0
5986
+ n := int (q )
5987
+ if q == float64 (n ) {
5988
+ n = n - 1
5989
+ }
5990
+ for i := 1 ; i <= n ; i ++ {
5991
+ if p1 <= 1 && term / eps <= finsum {
5992
+ break
5993
+ }
5994
+ xi := float64 (i )
5995
+ term = (q - xi + 1.0 ) * c * term / (p + q - xi )
5996
+ if term > 1.0 {
5997
+ ib = ib - 1
5998
+ term = term * sml
5999
+ }
6000
+ if ib == 0 {
6001
+ finsum = finsum + term
6002
+ }
6003
+ }
6004
+ ans = ans + finsum
6005
+ }
6006
+ if y != x || p != pin {
6007
+ ans = 1.0 - ans
6008
+ }
6009
+ ans = math .Max (math .Min (ans , 1.0 ), 0.0 )
6010
+ return ans
6011
+ }
6012
+
6013
+ // pbeta returns distribution function of the beta distribution.
6014
+ func pbeta (x , pin , qin float64 ) (ans float64 ) {
6015
+ eps := d1mach (3 )
6016
+ alneps := math .Log (eps )
6017
+ sml := d1mach (1 )
6018
+ alnsml := math .Log (sml )
6019
+ y := x
6020
+ p := pin
6021
+ q := qin
6022
+ if p / (p + q ) < x {
6023
+ y = 1.0 - y
6024
+ p = qin
6025
+ q = pin
6026
+ }
6027
+ if (p + q )* y / (p + 1.0 ) < eps {
6028
+ xb := p * math .Log (math .Max (y , sml )) - math .Log (p ) - logBeta (p , q )
6029
+ if xb > alnsml && y != 0.0 {
6030
+ ans = math .Exp (xb )
6031
+ }
6032
+ if y != x || p != pin {
6033
+ ans = 1.0 - ans
6034
+ }
6035
+ } else {
6036
+ ps := q - math .Floor (q )
6037
+ if ps == 0.0 {
6038
+ ps = 1.0
6039
+ }
6040
+ xb := p * math .Log (y ) - logBeta (ps , p ) - math .Log (p )
6041
+ if xb >= alnsml {
6042
+ ans = math .Exp (xb )
6043
+ term := ans * p
6044
+ if ps != 1.0 {
6045
+ n := int (math .Max (alneps / math .Log (y ), 4.0 ))
6046
+ for i := 1 ; i <= n ; i ++ {
6047
+ xi := float64 (i )
6048
+ term = term * (xi - ps ) * y / xi
6049
+ ans = ans + term / (p + xi )
6050
+ }
6051
+ }
6052
+ }
6053
+ ans = pbetaRaw (alnsml , ans , eps , p , pin , q , sml , x , y )
6054
+ }
6055
+ return ans
6056
+ }
6057
+
6058
+ // betainvProbIterator is a part of betainv for the inverse of the beta function.
6059
+ func betainvProbIterator (alpha1 , alpha3 , beta1 , beta2 , beta3 , logbeta , lower , maxCumulative , prob1 , prob2 , upper float64 , needSwap bool ) float64 {
6060
+ var i , j , prev , prop4 float64
6061
+ j = 1
6062
+ for prob := 0 ; prob < 1000 ; prob ++ {
6063
+ prop3 := pbeta (beta3 , alpha1 , beta1 )
6064
+ prop3 = (prop3 - prob1 ) * math .Exp (logbeta + prob2 * math .Log (beta3 )+ beta2 * math .Log (1.0 - beta3 ))
6065
+ if prop3 * prop4 <= 0 {
6066
+ prev = math .Max (math .Abs (j ), maxCumulative )
6067
+ }
6068
+ h := 1.0
6069
+ for iteratorCount := 0 ; iteratorCount < 1000 ; iteratorCount ++ {
6070
+ j = h * prop3
6071
+ if math .Abs (j ) < prev {
6072
+ i = beta3 - j
6073
+ if i >= 0 && i <= 1.0 {
6074
+ if prev <= alpha3 {
6075
+ return beta3
6076
+ }
6077
+ if math .Abs (prop3 ) <= alpha3 {
6078
+ return beta3
6079
+ }
6080
+ if i != 0 && i != 1.0 {
6081
+ break
6082
+ }
6083
+ }
6084
+ }
6085
+ h /= 3.0
6086
+ }
6087
+ if i == beta3 {
6088
+ return beta3
6089
+ }
6090
+ beta3 , prop4 = i , prop3
6091
+ }
6092
+ return beta3
6093
+ }
6094
+
6095
+ // betainv is an implementation for the quantile of the beta distribution.
6096
+ func betainv (probability , alpha , beta , lower , upper float64 ) float64 {
6097
+ minCumulative , maxCumulative := 1.0e-300 , 3.0e-308
6098
+ lowerBound , upperBound := maxCumulative , 1.0 - 2.22e-16
6099
+ needSwap := false
6100
+ var alpha1 , alpha2 , beta1 , beta2 , beta3 , prob1 , x , y float64
6101
+ if probability <= 0.5 {
6102
+ prob1 , alpha1 , beta1 = probability , alpha , beta
6103
+ } else {
6104
+ prob1 , alpha1 , beta1 , needSwap = 1.0 - probability , beta , alpha , true
6105
+ }
6106
+ logbeta := logBeta (alpha , beta )
6107
+ prob2 := math .Sqrt (- math .Log (prob1 * prob1 ))
6108
+ prob3 := prob2 - (prob2 * 0.27061 + 2.3075 )/ (prob2 * (prob2 * 0.04481 + 0.99229 )+ 1 )
6109
+ if alpha1 > 1 && beta1 > 1 {
6110
+ alpha2 , beta2 , prob2 = 1 / (alpha1 + alpha1 - 1 ), 1 / (beta1 + beta1 - 1 ), (prob3 * prob3 - 3 )/ 6
6111
+ x = 2 / (alpha2 + beta2 )
6112
+ y = prob3 * math .Sqrt (x + prob2 )/ x - (beta2 - alpha2 )* (prob2 + 5 / 6.0 - 2 / (x * 3 ))
6113
+ beta3 = alpha1 / (alpha1 + beta1 * math .Exp (y + y ))
6114
+ } else {
6115
+ beta2 , prob2 = 1 / (beta1 * 9 ), beta1 + beta1
6116
+ beta2 = prob2 * math .Pow (1 - beta2 + prob3 * math .Sqrt (beta2 ), 3 )
6117
+ if beta2 <= 0 {
6118
+ beta3 = 1 - math .Exp ((math .Log ((1 - prob1 )* beta1 )+ logbeta )/ beta1 )
6119
+ } else {
6120
+ beta2 = (prob2 + alpha1 * 4 - 2 ) / beta2
6121
+ if beta2 <= 1 {
6122
+ beta3 = math .Exp ((logbeta + math .Log (alpha1 * prob1 )) / alpha1 )
6123
+ } else {
6124
+ beta3 = 1 - 2 / (beta2 + 1 )
6125
+ }
6126
+ }
6127
+ }
6128
+ beta2 , prob2 = 1 - beta1 , 1 - alpha1
6129
+ if beta3 < lowerBound {
6130
+ beta3 = lowerBound
6131
+ } else if beta3 > upperBound {
6132
+ beta3 = upperBound
6133
+ }
6134
+ alpha3 := math .Max (minCumulative , math .Pow (10.0 , - 13.0 - 2.5 / (alpha1 * alpha1 )- 0.5 / (prob1 * prob1 )))
6135
+ beta3 = betainvProbIterator (alpha1 , alpha3 , beta1 , beta2 , beta3 , logbeta , lower , maxCumulative , prob1 , prob2 , upper , needSwap )
6136
+ if needSwap {
6137
+ beta3 = 1.0 - beta3
6138
+ }
6139
+ return (upper - lower )* beta3 + lower
6140
+ }
6141
+
6142
+ // FINV function calculates the inverse of the (right-tailed) F Probability
6143
+ // Distribution for a supplied probability. The syntax of the function is:
6144
+ //
6145
+ // FINV(probability,deg_freedom1,deg_freedom2)
6146
+ //
6147
+ func (fn * formulaFuncs ) FINV (argsList * list.List ) formulaArg {
6148
+ if argsList .Len () != 3 {
6149
+ return newErrorFormulaArg (formulaErrorVALUE , "FINV requires 3 arguments" )
6150
+ }
6151
+ var probability , d1 , d2 formulaArg
6152
+ if probability = argsList .Front ().Value .(formulaArg ).ToNumber (); probability .Type != ArgNumber {
6153
+ return probability
6154
+ }
6155
+ if d1 = argsList .Front ().Next ().Value .(formulaArg ).ToNumber (); d1 .Type != ArgNumber {
6156
+ return d1
6157
+ }
6158
+ if d2 = argsList .Back ().Value .(formulaArg ).ToNumber (); d2 .Type != ArgNumber {
6159
+ return d2
6160
+ }
6161
+ if probability .Number <= 0 || probability .Number > 1 {
6162
+ return newErrorFormulaArg (formulaErrorNUM , formulaErrorNUM )
6163
+ }
6164
+ if d1 .Number < 1 || d1 .Number >= math .Pow10 (10 ) {
6165
+ return newErrorFormulaArg (formulaErrorNUM , formulaErrorNUM )
6166
+ }
6167
+ if d2 .Number < 1 || d2 .Number >= math .Pow10 (10 ) {
6168
+ return newErrorFormulaArg (formulaErrorNUM , formulaErrorNUM )
6169
+ }
6170
+ return newNumberFormulaArg ((1 / betainv (1.0 - (1.0 - probability .Number ), d2 .Number / 2 , d1 .Number / 2 , 0 , 1 ) - 1.0 ) * (d2 .Number / d1 .Number ))
6171
+ }
6172
+
5838
6173
// NORMdotDIST function calculates the Normal Probability Density Function or
5839
6174
// the Cumulative Normal Distribution. Function for a supplied set of
5840
6175
// parameters. The syntax of the function is:
0 commit comments