JWS C Library
C language utility library
|
00001 /* 00002 * This work is licensed under a Creative Commons 00003 * Attribution-Noncommercial-Share Alike 3.0 United States License. 00004 * 00005 * http://creativecommons.org/licenses/by-nc-sa/3.0/us/ 00006 * 00007 * You are free: 00008 * 00009 * to Share - to copy, distribute, display, and perform the work 00010 * to Remix - to make derivative works 00011 * 00012 * Under the following conditions: 00013 * 00014 * Attribution. You must attribute the work in the manner specified by the 00015 * author or licensor (but not in any way that suggests that they endorse you 00016 * or your use of the work). 00017 * 00018 * Noncommercial. You may not use this work for commercial purposes. 00019 * 00020 * Share Alike. If you alter, transform, or build upon this work, you may 00021 * distribute the resulting work only under the same or similar license to 00022 * this one. 00023 * 00024 * For any reuse or distribution, you must make clear to others the license 00025 * terms of this work. The best way to do this is by including this header. 00026 * 00027 * Any of the above conditions can be waived if you get permission from the 00028 * copyright holder. 00029 * 00030 * Apart from the remix rights granted under this license, nothing in this 00031 * license impairs or restricts the author's moral rights. 00032 */ 00033 00034 00046 #include <jwsc/config.h> 00047 00048 #include <stdlib.h> 00049 #include <math.h> 00050 #include <assert.h> 00051 #include <inttypes.h> 00052 00053 #include "jwsc/base/limits.h" 00054 #include "jwsc/prob/pdf.h" 00055 #include "jwsc/prob/pmf.h" 00056 00057 00059 #define INV_E_SINGLE 0.3678794411714423f 00060 00062 #define INV_E_DOUBLE 0.36787944117144232159552377016146 00063 00065 #define ALMOST_ONE_SINGLE 0.9999999999999999 00066 00068 #define ALMOST_ONE_DOUBLE 0.99999999999999999999999999999999 00069 00070 00088 float poisson_pmf_f(float lambda, uint32_t n) 00089 { 00090 float p; 00091 int i; 00092 00093 if (lambda <= 0 && lambda == n) 00094 { 00095 return 1; 00096 } 00097 else if (lambda <= 0) 00098 { 00099 return 0; 00100 } 00101 00102 p = 1; 00103 00104 if (lambda < n) 00105 { 00106 for (i = n; i > (n - lambda); i--) 00107 { 00108 p *= lambda * INV_E_SINGLE * (1 / (float)i); 00109 } 00110 00111 for (; i > 0; i--) 00112 { 00113 p *= lambda * (1 / (float)i); 00114 } 00115 } 00116 else 00117 { 00118 for (i = n; i > 0; i--) 00119 { 00120 p *= lambda * INV_E_SINGLE * (1 / (float)i); 00121 } 00122 00123 p *= exp(-(lambda - n)); 00124 } 00125 00126 #if defined(JWSC_HAVE_ISNAN) && defined(JWSC_HAVE_ISINF) 00127 if (isnan(p) || isinf(p)) 00128 { 00129 return 0; 00130 } 00131 #endif 00132 00133 return p; 00134 } 00135 00146 double poisson_pmf_d(double lambda, uint32_t n) 00147 { 00148 double p; 00149 int i; 00150 00151 if (lambda <= 0 && lambda == n) 00152 { 00153 return 1; 00154 } 00155 else if (lambda <= 0) 00156 { 00157 return 0; 00158 } 00159 00160 p = 1; 00161 00162 if (lambda < n) 00163 { 00164 for (i = n; i > (n - lambda); i--) 00165 { 00166 p *= lambda * INV_E_DOUBLE * (1 / (double)i); 00167 } 00168 00169 for (; i > 0; i--) 00170 { 00171 p *= lambda * (1 / (double)i); 00172 } 00173 } 00174 else 00175 { 00176 for (i = n; i > 0; i--) 00177 { 00178 p *= lambda * INV_E_DOUBLE * (1 / (double)i); 00179 } 00180 00181 p *= exp(-(lambda - n)); 00182 } 00183 00184 #if defined(JWSC_HAVE_ISNAN) && defined(JWSC_HAVE_ISINF) 00185 if (isnan(p) || isinf(p)) 00186 { 00187 return 0; 00188 } 00189 #endif 00190 00191 return p; 00192 } 00193 00221 uint32_t sample_poisson_pmf_f 00222 ( 00223 float lambda, 00224 uint32_t a, 00225 uint32_t b 00226 ) 00227 { 00228 uint32_t s; 00229 uint32_t accept; 00230 float max_p, p, u; 00231 00232 if (lambda <= 0 && ((lambda >= a) && (lambda <= b))) 00233 { 00234 return (int)lambda; 00235 } 00236 else if (lambda <= 0) 00237 { 00238 return (a - lambda) < (lambda - b) ? a : b; 00239 } 00240 00241 max_p = poisson_pmf_f(lambda, floor(lambda + 0.5)); 00242 accept = 0; 00243 00244 while (!accept) 00245 { 00246 s = floor(sample_uniform_pdf_f((float)a, (float)b+1.0)); 00247 if (s == b+1) 00248 { 00249 s = b; 00250 } 00251 p = poisson_pmf_f(lambda, s); 00252 u = sample_uniform_pdf_f(0, max_p); 00253 00254 if (u <= p) 00255 { 00256 accept = 1; 00257 } 00258 } 00259 00260 return s; 00261 } 00262 00280 uint32_t sample_poisson_pmf_d 00281 ( 00282 double lambda, 00283 uint32_t a, 00284 uint32_t b 00285 ) 00286 { 00287 uint32_t s; 00288 uint32_t accept; 00289 double max_p, p, u; 00290 00291 if (lambda <= 0 && ((lambda >= a) && (lambda <= b))) 00292 { 00293 return (int)lambda; 00294 } 00295 else if (lambda <= 0) 00296 { 00297 return (a - lambda) < (lambda - b) ? a : b; 00298 } 00299 00300 max_p = poisson_pmf_d(lambda, floor(lambda + 0.5)); 00301 accept = 0; 00302 00303 while (!accept) 00304 { 00305 s = floor(sample_uniform_pdf_d((double)a, (double)b+1.0)); 00306 if (s == b+1) 00307 { 00308 s = b; 00309 } 00310 p = poisson_pmf_d(lambda, s); 00311 u = sample_uniform_pdf_d(0, max_p); 00312 00313 if (u <= p) 00314 { 00315 accept = 1; 00316 } 00317 } 00318 00319 return s; 00320 } 00321 00340 float bernoulli_pmf_f(float p, uint32_t n) 00341 { 00342 return n ? p : (1.0 - p); 00343 } 00344 00353 double bernoulli_pmf_d(double p, uint32_t n) 00354 { 00355 return n ? p : (1.0 - p); 00356 } 00357 00377 uint8_t sample_bernoulli_pmf_f(float p) 00378 { 00379 float u; 00380 00381 assert(p >= 0.0 && p <= 1.0); 00382 00383 u = sample_uniform_pdf_f(0.0, 1.0); 00384 00385 if (u <= p) 00386 { 00387 return 1; 00388 } 00389 00390 return 0; 00391 } 00392 00402 uint8_t sample_bernoulli_pmf_d(double p) 00403 { 00404 double u; 00405 00406 assert(p >= 0.0 && p <= 1.0); 00407 00408 u = sample_uniform_pdf_d(0.0, 1.0); 00409 00410 if (u <= p) 00411 { 00412 return 1; 00413 } 00414 00415 return 0; 00416 } 00417 00440 float geometric_pmf_f(float p, uint32_t n) 00441 { 00442 uint32_t i; 00443 float P; 00444 00445 assert(p > 0 && p < 1); 00446 00447 P = 1.0; 00448 00449 for (i = 0; i < n; i++) 00450 { 00451 P *= (1.0 - p); 00452 } 00453 00454 return P * p; 00455 } 00456 00469 double geometric_pmf_d(double p, uint32_t n) 00470 { 00471 uint32_t i; 00472 double P; 00473 00474 assert(p > 0 && p < 1); 00475 00476 P = 1.0; 00477 00478 for (i = 0; i < n; i++) 00479 { 00480 P *= (1.0 - p); 00481 } 00482 00483 return P * p; 00484 } 00485 00508 float log_geometric_pmf_f(float p, uint32_t n) 00509 { 00510 float q = 1 - p; 00511 00512 assert(p > 0 && p < 1); 00513 if (p < JWSC_MIN_LOG_ARG) 00514 { 00515 p = JWSC_MIN_LOG_ARG; 00516 } 00517 else if (q < JWSC_MIN_LOG_ARG) 00518 { 00519 q = JWSC_MIN_LOG_ARG; 00520 } 00521 00522 return log(p) + n*log(q); 00523 } 00524 00537 double log_geometric_pmf_d(double p, uint32_t n) 00538 { 00539 double q = 1 - p; 00540 00541 assert(p > 0 && p < 1); 00542 if (p < JWSC_MIN_LOG_ARG) 00543 { 00544 p = JWSC_MIN_LOG_ARG; 00545 } 00546 else if (q < JWSC_MIN_LOG_ARG) 00547 { 00548 q = JWSC_MIN_LOG_ARG; 00549 } 00550 00551 return log(p) + n*log(q); 00552 } 00553 00574 uint32_t sample_geometric_pmf_f(float p) 00575 { 00576 float u; 00577 00578 assert(p > 0 && p < 1); 00579 00580 u = sample_uniform_pdf_f(p, ALMOST_ONE_SINGLE); 00581 00582 return (uint32_t)floor((log(1.0 - u) / log(1.0 - p)) - 1.0); 00583 } 00584 00595 uint32_t sample_geometric_pmf_d(double p) 00596 { 00597 double u; 00598 00599 assert(p > 0 && p < 1); 00600 00601 u = sample_uniform_pdf_d(p, ALMOST_ONE_DOUBLE); 00602 00603 return (uint32_t)floor((log(1.0 - u) / log(1.0 - p)) - 1.0); 00604 } 00605