Module: Distribution::MathExtension::Beta
- Defined in:
- lib/distribution/math_extension/incomplete_beta.rb
Class Method Summary collapse
-
.log_beta(x, y, with_error = false) ⇒ Object
Based on gsl_sf_lnbeta_e and gsl_sf_lnbeta_sgn_e Returns result and sign in an array.
Class Method Details
.log_beta(x, y, with_error = false) ⇒ Object
Based on gsl_sf_lnbeta_e and gsl_sf_lnbeta_sgn_e Returns result and sign in an array. If with_error is specified, also returns the error.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/distribution/math_extension/incomplete_beta.rb', line 10 def log_beta(x, y, with_error = false) sign = nil fail(ArgumentError, 'x and y must be nonzero') if x == 0.0 || y == 0.0 fail(ArgumentError, 'not defined for negative integers') if [x, y].any? { |v| v < 0 } # See if we can handle the positive case with min/max < 0.2 if x > 0 && y > 0 min, max = [x, y].minmax ratio = min.quo(max) if ratio < 0.2 gsx = Gammastar.evaluate(x, with_error) gsy = Gammastar.evaluate(y, with_error) gsxy = Gammastar.evaluate(x + y, with_error) lnopr = Log.log_1plusx(ratio, with_error) gsx, gsx_err, gsy, gsy_err, gsxy, gsxy_err, lnopr, lnopr_err = [gsx, gsy, gsxy, lnopr].flatten if with_error lnpre = Math.log((gsx * gsy).quo(gsxy) * Math::SQRT2 * Math::SQRTPI) lnpre_err = gsx_err.quo(gsx) + gsy_err(gsy) + gsxy_err.quo(gsxy) if with_error t1 = min * Math.log(ratio) t2 = 0.5 * Math.log(min) t3 = (x + y - 0.5) * lnopr lnpow = t1 - t2 - t3 lnpow_err = Float::EPSILON * (t1.abs + t2.abs + t3.abs) + (x + y - 0.5).abs * lnopr_err if with_error result = lnpre + lnpow error = lnpre_err + lnpow_err + 2.0 * Float::EPSILON * result.abs if with_error return with_error ? [result, 1.0, error] : [result, 1.0] end end # General case: fallback lgx, sgx = Math.lgamma(x) lgy, sgy = Math.lgamma(y) lgxy, sgxy = Math.lgamma(x + y) sgn = sgx * sgy * sgxy fail('Domain error: sign is -') if sgn == -1 result = lgx + lgy - lgxy if with_error lgx_err, lgy_err, lgxy_err = begin STDERR.puts('Warning: Error is unknown for Math::lgamma, guessing.') [Math::EPSILON, Math::EPSILON, Math::EPSILON] end error = lgx_err + lgy_err + lgxy_err + Float::EPSILON * (lgx.abs + lgy.abs + lgxy.abs) + 2.0 * (Float::EPSILON) * result.abs return [result, sgn, error] else return [result, sgn] end end |