📄 specfun.cc
字号:
//// This file is a part of the Bayes Blocks library//// Copyright (C) 2001-2006 Markus Harva, Antti Honkela, Alexander// Ilin, Tapani Raiko, Harri Valpola and Tomas 謘tman.//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2, or (at your option)// any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License (included in file License.txt in the// program package) for more details.///* * ==================================================== * Portions Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunPro, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== *///// $Id: SpecFun.cc 5 2006-10-26 09:44:54Z ah $#include <math.h>#include "config.h"#include "SpecFun.h"const double DIGAMMA_S = 1e-5;const double DIGAMMA_C = 8.5;const double DIGAMMA_S3 = 1.0/12;const double DIGAMMA_S4 = 1.0/120;const double DIGAMMA_S5 = 1.0/252;const double DIGAMMA_D1 = -0.5772156649015328605195174;#ifndef M_PI#define M_PI 4*atan((double)1.0)#endif // not defined M_PIdouble DiGamma(double x) { double y = 0.0; double r = 0.0; double xn = x; if (xn < 0) { throw ValueException(); } if (xn <= DIGAMMA_S) y = DIGAMMA_D1 - 1.0 / xn; else { while (xn < DIGAMMA_C) { y = y - 1.0 / xn; xn = xn + 1; } r = 1.0 / xn; y = y + log(xn) - .5 * r; r = r * r; y = y - r * (DIGAMMA_S3 - r * (DIGAMMA_S4 - r*DIGAMMA_S5)); } return y;}double NormPdf(double x, double m, double v) { return 1 / sqrt(2*M_PI*v) * exp(-Sqr(m - x) / (2 * v));}#ifdef BAD_MATHLIB/* @(#)er_lgamma.c 5.1 93/09/24 *//* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunPro, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */// static char rcsid[] = "NetBSD: e_lgamma_r.c,v 1.7 1995/05/10 20:45:42 jtc Exp";/* __ieee754_lgamma_r(x, signgamp) * Reentrant version of the logarithm of the Gamma function * with user provide pointer for the sign of Gamma(x). * * Method: * 1. Argument Reduction for 0 < x <= 8 * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may * reduce x to a number in [1.5,2.5] by * lgamma(1+s) = log(s) + lgamma(s) * for example, * lgamma(7.3) = log(6.3) + lgamma(6.3) * = log(6.3*5.3) + lgamma(5.3) * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) * 2. Polynomial approximation of lgamma around its * minimun ymin=1.461632144968362245 to maintain monotonicity. * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use * Let z = x-ymin; * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) * where * poly(z) is a 14 degree polynomial. * 2. Rational approximation in the primary interval [2,3] * We use the following approximation: * s = x-2.0; * lgamma(x) = 0.5*s + s*P(s)/Q(s) * with accuracy * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 * Our algorithms are based on the following observation * * zeta(2)-1 2 zeta(3)-1 3 * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... * 2 3 * * where Euler = 0.5771... is the Euler constant, which is very * close to 0.5. * * 3. For x>=8, we have * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... * (better formula: * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) * Let z = 1/x, then we approximation * f(z) = lgamma(x) - (x-0.5)(log(x)-1) * by * 3 5 11 * w = w0 + w1*z + w2*z + w3*z + ... + w6*z * where * |w - f(z)| < 2**-58.74 * * 4. For negative x, since (G is gamma function) * -x*G(-x)*G(x) = pi/sin(pi*x), * we have * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 * Hence, for x<0, signgam = sign(sin(pi*x)) and * lgamma(x) = log(|Gamma(x)|) * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); * Note: one should avoid compute pi*(-x) directly in the * computation of sin(pi*(-x)). * * 5. Special Cases * lgamma(2+s) ~ s*(1-Euler) for tiny s * lgamma(1)=lgamma(2)=0 * lgamma(x) ~ -log(x) for tiny x * lgamma(0) = lgamma(inf) = inf * lgamma(-integer) = +-inf * */// ASSUME 32 bit intstypedef int int32_t;typedef unsigned int u_int32_t;// ASSUME little endian byte ordertypedef union { double value; struct { u_int32_t lsw; u_int32_t msw; } parts;} ieee_double_shape_type;#define EXTRACT_WORDS(ix0,ix1,d) \do { \ ieee_double_shape_type ew_u; \ ew_u.value = (d); \ (ix0) = ew_u.parts.msw; \ (ix1) = ew_u.parts.lsw; \} while (0)#define GET_HIGH_WORD(i,d) \do { \ ieee_double_shape_type gh_u; \ gh_u.value = (d); \ (i) = gh_u.parts.msw; \} while (0)#define GET_LOW_WORD(i,d) \do { \ ieee_double_shape_type gl_u; \ gl_u.value = (d); \ (i) = gl_u.parts.lsw; \} while (0)#define INSERT_WORDS(d,ix0,ix1) \do { \ ieee_double_shape_type iw_u; \ iw_u.parts.msw = (ix0); \ iw_u.parts.lsw = (ix1); \ (d) = iw_u.value; \} while (0)#define SET_LOW_WORD(d,v) \do { \ ieee_double_shape_type sl_u; \ sl_u.value = (d); \ sl_u.parts.lsw = (v); \ (d) = sl_u.value; \} while (0)#define __ieee754_log(x) log(x)#define __ieee754_exp(x) exp(x)static const double two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 *//* tt = -(tail of tf) */tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */static const double zero= 0.00000000000000000000e+00;static const double S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */double__kernel_sin(double x, double y, int iy){ double z,r,v; int32_t ix; GET_HIGH_WORD(ix,x); ix &= 0x7fffffff; /* high word of x */ if(ix<0x3e400000) /* |x| < 2**-27 */ {if((int)x==0) return x;} /* generate inexact */ z = x*x; v = z*x; r = S2+z*(S3+z*(S4+z*(S5+z*S6))); if(iy==0) return x+v*(S1+z*r); else return x-((z*(half*y-v*r)-y)-v*S1);}static const double C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */double__kernel_cos(double x, double y){ double a,hz,z,r,qx; int32_t ix; GET_HIGH_WORD(ix,x); ix &= 0x7fffffff; /* ix = |x|'s high word*/ if(ix<0x3e400000) { /* if x < 2**27 */ if(((int)x)==0) return one; /* generate inexact */ } z = x*x; r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); if(ix < 0x3FD33333) /* if |x| < 0.3 */ return one - (0.5*z - (z*r - x*y)); else { if(ix > 0x3fe90000) { /* x > 0.78125 */ qx = 0.28125; } else { INSERT_WORDS(qx,ix-0x00200000,0); /* x/4 */ } hz = 0.5*z-qx; a = one-qx; return a - (hz - (z*r-x*y)); }}static doublesin_pi(double x){ double y,z; int n,ix; GET_HIGH_WORD(ix,x); ix &= 0x7fffffff; if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0); y = -x; /* x is assume negative */ /* * argument reduction, make sure inexact flag not raised if input * is an integer */ z = floor(y); if(z!=y) { /* inexact anyway */ y *= 0.5; y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */ n = (int) (y*4.0); } else { if(ix>=0x43400000) { y = zero; n = 0; /* y must be even */ } else { if(ix<0x43300000) z = y+two52; /* exact */ GET_LOW_WORD(n,z); n &= 1; y = n; n<<= 2; } } switch (n) { case 0: y = __kernel_sin(pi*y,zero,0); break; case 1: case 2: y = __kernel_cos(pi*(0.5-y),zero); break; case 3: case 4: y = __kernel_sin(pi*(one-y),zero,0); break; case 5: case 6: y = -__kernel_cos(pi*(y-1.5),zero); break; default: y = __kernel_sin(pi*(y-2.0),zero,0); break; } return -y;}doubleLogGamma(double x)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -