diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-08-31 06:21:08 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-08-31 06:21:08 -0700 |
commit | 5717a5656e0486daba71ae0eae733f252840cffd (patch) | |
tree | d541a482d3d4c82710e35d7042e133283e698cfb /arith.c | |
parent | a3d69ff4b9ca5c485f9d199a2f071aa61469a55f (diff) | |
download | txr-5717a5656e0486daba71ae0eae733f252840cffd.tar.gz txr-5717a5656e0486daba71ae0eae733f252840cffd.tar.bz2 txr-5717a5656e0486daba71ae0eae733f252840cffd.zip |
New function: inverse of cumulative normal dist.
* arith.c (inv_cum_norm): New function.
* arith.h (inv_cum_norm): Declared.
* eval.c (eval_init): Register inv-cum-norm intrinsic.
* txr.1: Documented.
Diffstat (limited to 'arith.c')
-rw-r--r-- | arith.c | 24 |
1 files changed, 24 insertions, 0 deletions
@@ -2725,6 +2725,30 @@ val cum_norm_dist(val arg) } } +/* + * Source: + * Odeh and Evans approximation. + * 1974 + */ +val inv_cum_norm(val arg) +{ + val arg_flo = to_float(lit("inv-cum-norm"), arg); + double p = c_flo(arg_flo); + int is_upper_half = (p >= 0.5); + double r = is_upper_half ? 1 - p : p; + if (r < 1E-20) { + return flo(is_upper_half ? 10 : -10); + } else { + double y = sqrt(-2*log(r)); + double a = ((((4.53642210148e-5*y + 0.0204231210245)*y + + 0.342242088547)*y + 1)*y + 0.322232431088); + double b = ((((0.0038560700634*y + 0.10353775285)*y + + 0.531103462366)*y + 0.588581570495)*y + 0.099348462606); + double z = y - a / b; + return flo(is_upper_half ? z : -z); + } +} + static val rising_product(val m, val n) { val acc; |