Lines 44-53
Link Here
|
44 |
#include <vector> |
44 |
#include <vector> |
45 |
#include <algorithm> |
45 |
#include <algorithm> |
46 |
|
46 |
|
47 |
#include <boost/math/special_functions/atanh.hpp> |
|
|
48 |
#include <boost/math/special_functions/expm1.hpp> |
49 |
#include <boost/math/special_functions/log1p.hpp> |
50 |
|
51 |
using ::std::vector; |
47 |
using ::std::vector; |
52 |
using namespace formula; |
48 |
using namespace formula; |
53 |
|
49 |
|
Lines 577-667
Link Here
|
577 |
return fSumNum/fSumDenom; |
573 |
return fSumNum/fSumDenom; |
578 |
} |
574 |
} |
579 |
|
575 |
|
580 |
// The algorithm is based on tgamma in gamma.hpp |
|
|
581 |
// in math library from http://www.boost.org |
582 |
/** You must ensure fZ>0; fZ>171.624376956302 will overflow. */ |
583 |
double lcl_GetGammaHelper(double fZ) |
584 |
{ |
585 |
double fGamma = lcl_getLanczosSum(fZ); |
586 |
const double fg = 6.024680040776729583740234375; |
587 |
double fZgHelp = fZ + fg - 0.5; |
588 |
// avoid intermediate overflow |
589 |
double fHalfpower = pow( fZgHelp, fZ / 2 - 0.25); |
590 |
fGamma *= fHalfpower; |
591 |
fGamma /= exp(fZgHelp); |
592 |
fGamma *= fHalfpower; |
593 |
if (fZ <= 20.0 && fZ == ::rtl::math::approxFloor(fZ)) |
594 |
fGamma = ::rtl::math::round(fGamma); |
595 |
return fGamma; |
596 |
} |
597 |
|
576 |
|
598 |
// The algorithm is based on tgamma in gamma.hpp |
|
|
599 |
// in math library from http://www.boost.org |
600 |
/** You must ensure fZ>0 */ |
601 |
double lcl_GetLogGammaHelper(double fZ) |
602 |
{ |
603 |
const double fg = 6.024680040776729583740234375; |
604 |
double fZgHelp = fZ + fg - 0.5; |
605 |
return log( lcl_getLanczosSum(fZ)) + (fZ-0.5) * log(fZgHelp) - fZgHelp; |
606 |
} |
607 |
|
608 |
/** You must ensure non integer arguments for fZ<1 */ |
577 |
/** You must ensure non integer arguments for fZ<1 */ |
609 |
double ScInterpreter::GetGamma(double fZ) |
578 |
double ScInterpreter::GetGamma(double fZ) |
610 |
{ |
579 |
{ |
611 |
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetGamma" ); |
580 |
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "bst", "ScInterpreter::GetGamma" ); |
612 |
const double fLogPi = log(F_PI); |
|
|
613 |
const double fLogDblMax = log( ::std::numeric_limits<double>::max()); |
614 |
|
615 |
if (fZ > fMaxGammaArgument) |
581 |
if (fZ > fMaxGammaArgument) |
616 |
{ |
582 |
{ |
617 |
SetError(errIllegalFPOperation); |
583 |
SetError(errIllegalFPOperation); |
618 |
return HUGE_VAL; |
584 |
return HUGE_VAL; |
619 |
} |
585 |
} |
620 |
|
586 |
return ::boost::math::tgamma(fZ); |
621 |
if (fZ >= 1.0) |
|
|
622 |
return lcl_GetGammaHelper(fZ); |
623 |
|
624 |
if (fZ >= 0.5) // shift to x>=1 using Gamma(x)=Gamma(x+1)/x |
625 |
return lcl_GetGammaHelper(fZ+1) / fZ; |
626 |
|
627 |
if (fZ >= -0.5) // shift to x>=1, might overflow |
628 |
{ |
629 |
double fLogTest = lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log( fabs(fZ)); |
630 |
if (fLogTest >= fLogDblMax) |
631 |
{ |
632 |
SetError( errIllegalFPOperation); |
633 |
return HUGE_VAL; |
634 |
} |
635 |
return lcl_GetGammaHelper(fZ+2) / (fZ+1) / fZ; |
636 |
} |
637 |
// fZ<-0.5 |
638 |
// Use Euler's reflection formula: gamma(x)= pi/ ( gamma(1-x)*sin(pi*x) ) |
639 |
double fLogDivisor = lcl_GetLogGammaHelper(1-fZ) + log( fabs( ::rtl::math::sin( F_PI*fZ))); |
640 |
if (fLogDivisor - fLogPi >= fLogDblMax) // underflow |
641 |
return 0.0; |
642 |
|
643 |
if (fLogDivisor<0.0) |
644 |
if (fLogPi - fLogDivisor > fLogDblMax) // overflow |
645 |
{ |
646 |
SetError(errIllegalFPOperation); |
647 |
return HUGE_VAL; |
648 |
} |
649 |
|
650 |
return exp( fLogPi - fLogDivisor) * ((::rtl::math::sin( F_PI*fZ) < 0.0) ? -1.0 : 1.0); |
651 |
} |
587 |
} |
652 |
|
588 |
|
653 |
|
589 |
|
654 |
/** You must ensure fZ>0 */ |
590 |
/** You must ensure fZ>0 */ |
655 |
double ScInterpreter::GetLogGamma(double fZ) |
591 |
double ScInterpreter::GetLogGamma(double fZ) |
656 |
{ |
592 |
{ |
657 |
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetLogGamma" ); |
593 |
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "bst", "ScInterpreter::GetLogGamma" ); |
658 |
if (fZ >= fMaxGammaArgument) |
594 |
return ::boost::math::lgamma(fZ); |
659 |
return lcl_GetLogGammaHelper(fZ); |
|
|
660 |
if (fZ >= 1.0) |
661 |
return log(lcl_GetGammaHelper(fZ)); |
662 |
if (fZ >= 0.5) |
663 |
return log( lcl_GetGammaHelper(fZ+1) / fZ); |
664 |
return lcl_GetLogGammaHelper(fZ+2) - log(fZ+1) - log(fZ); |
665 |
} |
595 |
} |
666 |
|
596 |
|
667 |
double ScInterpreter::GetFDist(double x, double fF1, double fF2) |
597 |
double ScInterpreter::GetFDist(double x, double fF1, double fF2) |
Lines 857-864
Link Here
|
857 |
fLanczos *= sqrt((fABgm/(fA+fgm))/(fB+fgm)); |
787 |
fLanczos *= sqrt((fABgm/(fA+fgm))/(fB+fgm)); |
858 |
double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm)) |
788 |
double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm)) |
859 |
double fTempB = fA/(fB+fgm); |
789 |
double fTempB = fA/(fB+fgm); |
860 |
double fResult = exp(-fA * ::boost::math::log1p(fTempA) |
790 |
double fResult = exp(-fA * ::rtl::math::log1p(fTempA) |
861 |
-fB * ::boost::math::log1p(fTempB)-fgm); |
791 |
-fB * ::rtl::math::log1p(fTempB)-fgm); |
862 |
fResult *= fLanczos; |
792 |
fResult *= fLanczos; |
863 |
return fResult; |
793 |
return fResult; |
864 |
} |
794 |
} |
Lines 886-893
Link Here
|
886 |
fLogLanczos += 0.5*(log(fABgm)-log(fA+fgm)-log(fB+fgm)); |
816 |
fLogLanczos += 0.5*(log(fABgm)-log(fA+fgm)-log(fB+fgm)); |
887 |
double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm)) |
817 |
double fTempA = fB/(fA+fgm); // (fA+fgm)/fABgm = 1 / ( 1 + fB/(fA+fgm)) |
888 |
double fTempB = fA/(fB+fgm); |
818 |
double fTempB = fA/(fB+fgm); |
889 |
double fResult = -fA * ::boost::math::log1p(fTempA) |
819 |
double fResult = -fA * ::rtl::math::log1p(fTempA) |
890 |
-fB * ::boost::math::log1p(fTempB)-fgm; |
820 |
-fB * ::rtl::math::log1p(fTempB)-fgm; |
891 |
fResult += fLogLanczos; |
821 |
fResult += fLogLanczos; |
892 |
return fResult; |
822 |
return fResult; |
893 |
} |
823 |
} |
Lines 908-914
Link Here
|
908 |
return HUGE_VAL; |
838 |
return HUGE_VAL; |
909 |
} |
839 |
} |
910 |
if (fX <= 0.01) |
840 |
if (fX <= 0.01) |
911 |
return fB + fB * ::boost::math::expm1((fB-1.0) * ::boost::math::log1p(-fX)); |
841 |
return fB + fB * ::rtl::math::expm1((fB-1.0) * ::rtl::math::log1p(-fX)); |
912 |
else |
842 |
else |
913 |
return fB * pow(0.5-fX+0.5,fB-1.0); |
843 |
return fB * pow(0.5-fX+0.5,fB-1.0); |
914 |
} |
844 |
} |
Lines 947-953
Link Here
|
947 |
// normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b) |
877 |
// normal cases; result x^(a-1)*(1-x)^(b-1)/Beta(a,b) |
948 |
const double fLogDblMax = log( ::std::numeric_limits<double>::max()); |
878 |
const double fLogDblMax = log( ::std::numeric_limits<double>::max()); |
949 |
const double fLogDblMin = log( ::std::numeric_limits<double>::min()); |
879 |
const double fLogDblMin = log( ::std::numeric_limits<double>::min()); |
950 |
double fLogY = (fX < 0.1) ? ::boost::math::log1p(-fX) : log(0.5-fX+0.5); |
880 |
double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5); |
951 |
double fLogX = log(fX); |
881 |
double fLogX = log(fX); |
952 |
double fAm1LogX = (fA-1.0) * fLogX; |
882 |
double fAm1LogX = (fA-1.0) * fLogX; |
953 |
double fBm1LogY = (fB-1.0) * fLogY; |
883 |
double fBm1LogY = (fB-1.0) * fLogY; |
Lines 1028-1040
Link Here
|
1028 |
return pow(fXin, fAlpha); |
958 |
return pow(fXin, fAlpha); |
1029 |
if (fAlpha == 1.0) |
959 |
if (fAlpha == 1.0) |
1030 |
// 1.0 - pow(1.0-fX,fBeta) is not accurate enough |
960 |
// 1.0 - pow(1.0-fX,fBeta) is not accurate enough |
1031 |
return -::boost::math::expm1(fBeta * ::boost::math::log1p(-fXin)); |
961 |
return -::rtl::math::expm1(fBeta * ::rtl::math::log1p(-fXin)); |
1032 |
//FIXME: need special algorithm for fX near fP for large fA,fB |
962 |
//FIXME: need special algorithm for fX near fP for large fA,fB |
1033 |
double fResult; |
963 |
double fResult; |
1034 |
// I use always continued fraction, power series are neither |
964 |
// I use always continued fraction, power series are neither |
1035 |
// faster nor more accurate. |
965 |
// faster nor more accurate. |
1036 |
double fY = (0.5-fXin)+0.5; |
966 |
double fY = (0.5-fXin)+0.5; |
1037 |
double flnY = ::boost::math::log1p(-fXin); |
967 |
double flnY = ::rtl::math::log1p(-fXin); |
1038 |
double fX = fXin; |
968 |
double fX = fXin; |
1039 |
double flnX = log(fXin); |
969 |
double flnX = log(fXin); |
1040 |
double fA = fAlpha; |
970 |
double fA = fAlpha; |
Lines 1145-1151
Link Here
|
1145 |
if (fabs(fVal) >= 1.0) |
1075 |
if (fabs(fVal) >= 1.0) |
1146 |
PushIllegalArgument(); |
1076 |
PushIllegalArgument(); |
1147 |
else |
1077 |
else |
1148 |
PushDouble( ::boost::math::atanh( fVal)); |
1078 |
PushDouble( ::rtl::math::atanh( fVal)); |
1149 |
} |
1079 |
} |
1150 |
|
1080 |
|
1151 |
void ScInterpreter::ScFisherInv() |
1081 |
void ScInterpreter::ScFisherInv() |