diff options
Diffstat (limited to 'Build/source/texk/web2c/mplibdir/mpmathdecimal.w')
-rw-r--r-- | Build/source/texk/web2c/mplibdir/mpmathdecimal.w | 143 |
1 files changed, 133 insertions, 10 deletions
diff --git a/Build/source/texk/web2c/mplibdir/mpmathdecimal.w b/Build/source/texk/web2c/mplibdir/mpmathdecimal.w index 2d5a7e3d0a0..d0550c51a80 100644 --- a/Build/source/texk/web2c/mplibdir/mpmathdecimal.w +++ b/Build/source/texk/web2c/mplibdir/mpmathdecimal.w @@ -68,6 +68,7 @@ static void mp_number_angle_to_scaled (mp_number *A); static void mp_number_fraction_to_scaled (mp_number *A); static void mp_number_scaled_to_fraction (mp_number *A); static void mp_number_scaled_to_angle (mp_number *A); +static void mp_decimal_m_unif_rand (MP mp, mp_number *ret, mp_number x_orig); static void mp_decimal_m_norm_rand (MP mp, mp_number *ret); static void mp_decimal_m_exp (MP mp, mp_number *ret, mp_number x_orig); static void mp_decimal_m_log (MP mp, mp_number *ret, mp_number x_orig); @@ -542,6 +543,7 @@ void * mp_initialize_decimal_math (MP mp) { math->n_arg = mp_decimal_n_arg; math->m_log = mp_decimal_m_log; math->m_exp = mp_decimal_m_exp; + math->m_unif_rand = mp_decimal_m_unif_rand; math->m_norm_rand = mp_decimal_m_norm_rand; math->pyth_add = mp_decimal_pyth_add; math->pyth_sub = mp_decimal_pyth_sub; @@ -1424,8 +1426,8 @@ int mp_round_unscaled(mp_number x_orig) { @c void mp_number_floor (mp_number *i) { - int round = set.round; - set.round = DEC_ROUND_FLOOR; + int round = set.round; + set.round = DEC_ROUND_FLOOR; decNumberToIntegralValue(i->data.num, i->data.num, &set); set.round = round; } @@ -1724,6 +1726,81 @@ mp_number_to_double(*n_cos), mp_number_to_double(*n_sin)); mp_check_decNumber(mp, n_sin->data.num, &set); } +@ This is the http://www-cs-faculty.stanford.edu/~uno/programs/rng.c +with small cosmetic modifications. + +@c +#define KK 100 /* the long lag */ +#define LL 37 /* the short lag */ +#define MM (1L<<30) /* the modulus */ +#define mod_diff(x,y) (((x)-(y))&(MM-1)) /* subtraction mod MM */ +/* */ +static long ran_x[KK]; /* the generator state */ +/* */ +static void ran_array(long aa[],int n) /* put n new random numbers in aa */ + /* long aa[] destination */ + /* int n array length (must be at least KK) */ +{ + register int i,j; + for (j=0;j<KK;j++) aa[j]=ran_x[j]; + for (;j<n;j++) aa[j]=mod_diff(aa[j-KK],aa[j-LL]); + for (i=0;i<LL;i++,j++) ran_x[i]=mod_diff(aa[j-KK],aa[j-LL]); + for (;i<KK;i++,j++) ran_x[i]=mod_diff(aa[j-KK],ran_x[i-LL]); +} +/* */ +/* the following routines are from exercise 3.6--15 */ +/* after calling ran_start, get new randoms by, e.g., "x=ran_arr_next()" */ +/* */ +#define QUALITY 1009 /* recommended quality level for high-res use */ +static long ran_arr_buf[QUALITY]; +static long ran_arr_dummy=-1, ran_arr_started=-1; +static long *ran_arr_ptr=&ran_arr_dummy; /* the next random number, or -1 */ +/* */ +#define TT 70 /* guaranteed separation between streams */ +#define is_odd(x) ((x)&1) /* units bit of x */ +/* */ +static void ran_start(long seed) /* do this before using ran_array */ + /* long seed selector for different streams */ +{ + register int t,j; + long x[KK+KK-1]; /* the preparation buffer */ + register long ss=(seed+2)&(MM-2); + for (j=0;j<KK;j++) { + x[j]=ss; /* bootstrap the buffer */ + ss<<=1; if (ss>=MM) ss-=MM-2; /* cyclic shift 29 bits */ + } + x[1]++; /* make x[1] (and only x[1]) odd */ + for (ss=seed&(MM-1),t=TT-1; t; ) { + for (j=KK-1;j>0;j--) x[j+j]=x[j], x[j+j-1]=0; /* "square" */ + for (j=KK+KK-2;j>=KK;j--) + x[j-(KK-LL)]=mod_diff(x[j-(KK-LL)],x[j]), + x[j-KK]=mod_diff(x[j-KK],x[j]); + if (is_odd(ss)) { /* "multiply by z" */ + for (j=KK;j>0;j--) x[j]=x[j-1]; + x[0]=x[KK]; /* shift the buffer cyclically */ + x[LL]=mod_diff(x[LL],x[KK]); + } + if (ss) ss>>=1; else t--; + } + for (j=0;j<LL;j++) ran_x[j+KK-LL]=x[j]; + for (;j<KK;j++) ran_x[j-LL]=x[j]; + for (j=0;j<10;j++) ran_array(x,KK+KK-1); /* warm things up */ + ran_arr_ptr=&ran_arr_started; +} +/* */ +#define ran_arr_next() (*ran_arr_ptr>=0? *ran_arr_ptr++: ran_arr_cycle()) +static long ran_arr_cycle(void) +{ + if (ran_arr_ptr==&ran_arr_dummy) + ran_start(314159L); /* the user forgot to initialize */ + ran_array(ran_arr_buf,QUALITY); + ran_arr_buf[KK]=-1; + ran_arr_ptr=ran_arr_buf+1; + return ran_arr_buf[0]; +} + + + @ To initialize the |randoms| table, we call the following routine. @c @@ -1746,6 +1823,9 @@ void mp_init_randoms (MP mp, int seed) { mp_new_randoms (mp); mp_new_randoms (mp); mp_new_randoms (mp); /* ``warm up'' the array */ + + ran_start((unsigned long) seed); + } @ @c @@ -1754,14 +1834,21 @@ void mp_decimal_number_modulo (mp_number *a, mp_number b) { } +@ To consume a random integer for the uniform generator, the program below will say `|next_unif_random|'. - - - - - - - +@c +static void mp_next_unif_random (MP mp, mp_number *ret) { + decNumber a; + decNumber b; + unsigned long int op; + (void)mp; + op = (unsigned)ran_arr_next(); + decNumberFromInt32(&a, op); + decNumberFromInt32(&b, MM); + decNumberDivide (&a, &a, &b, &set); /* a = a/b */ + decNumberCopy(ret->data.num, &a); + mp_check_decNumber(mp, ret->data.num, &set); +} @ To consume a random fraction, the program below will say `|next_random|'. @@ -1776,6 +1863,43 @@ static void mp_next_random (MP mp, mp_number *ret) { } +@ To produce a uniform random number in the range |0<=u<x| or |0>=u>x| +or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here. + +Note that the call of |take_fraction| will produce the values 0 and~|x| +with about half the probability that it will produce any other particular +values between 0 and~|x|, because it rounds its answers. + +@c +static void mp_decimal_m_unif_rand (MP mp, mp_number *ret, mp_number x_orig) { + mp_number y; /* trial value */ + mp_number x, abs_x; + mp_number u; + new_fraction (y); + new_number (x); + new_number (abs_x); + new_number (u); + mp_number_clone (&x, x_orig); + mp_number_clone (&abs_x, x); + mp_decimal_abs (&abs_x); + mp_next_unif_random(mp, &u); + decNumberMultiply (y.data.num, abs_x.data.num, u.data.num, &set); + free_number (u); + if (mp_number_equal(y, abs_x)) { + mp_number_clone (ret, ((math_data *)mp->math)->zero_t); + } else if (mp_number_greater(x, ((math_data *)mp->math)->zero_t)) { + mp_number_clone (ret, y); + } else { + mp_number_clone (ret, y); + mp_number_negate (ret); + } + free_number (abs_x); + free_number (x); + free_number (y); +} + + + @ Finally, a normal deviate with mean zero and unit standard deviation can readily be obtained with the ratio method (Algorithm 3.4.1R in {\sl The Art of Computer Programming\/}). @@ -1810,7 +1934,6 @@ static void mp_decimal_m_norm_rand (MP mp, mp_number *ret) { mp_number_clone (&xa, r); mp_decimal_m_log (mp,&la, u); mp_set_decimal_from_substraction(&la, ((math_data *)mp->math)->twelve_ln_2_k, la); - /*mp_decimal_ab_vs_cd (mp,&ab_vs_cd, ((math_data *)mp->math)->one_k, la, xa, xa);*/ mp_ab_vs_cd (mp,&ab_vs_cd, ((math_data *)mp->math)->one_k, la, xa, xa); } while (mp_number_less(ab_vs_cd,((math_data *)mp->math)->zero_t)); mp_number_clone (ret, xa); |