[Change] Now using normal distibution for accuracy for weapons (clamped).
This commit is contained in:
		
							parent
							
								
									80bab44b8b
								
							
						
					
					
						commit
						a60c84465f
					
				
							
								
								
									
										125
									
								
								src/rng.c
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								src/rng.c
									
									
									
									
									
								
							| @ -2,12 +2,14 @@ | ||||
| #include <math.h> | ||||
| #include <unistd.h> | ||||
| #include <time.h> | ||||
| #include <errno.h> | ||||
| #ifdef LINUX | ||||
| #include <sys/time.h> | ||||
| #include <fcntl.h> | ||||
| #endif | ||||
| #include <SDL.h> | ||||
| 
 | ||||
| #include "lephisto.h" | ||||
| #include "rng.h" | ||||
| #include "log.h" | ||||
| 
 | ||||
| @ -114,3 +116,126 @@ double randfp(void) { | ||||
|   return m / m_div; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Calculate N(x) where N is the normal distribution. | ||||
|  * | ||||
|  * Approximates to a power series: | ||||
|  * | ||||
|  *  N(x) = 1 - n(x)*(b1*t + b2*t^2 + b3*t^3 + b4*t^4 + b5*t^5) + Err | ||||
|  *  where t = 1 / (1 + 0.2316419*x) | ||||
|  * | ||||
|  * Maximum absolute error is 7.5e^-8. | ||||
|  */ | ||||
| double Normal(double x) { | ||||
|   double t; | ||||
|   double series; | ||||
|   const double b1 =  0.319381530; | ||||
|   const double b2 = -0.356563782; | ||||
|   const double b3 =  1.781477937; | ||||
|   const double b4 = -1.821255978; | ||||
|   const double b5 =  1.330274429; | ||||
|   const double p  =  0.2316419; | ||||
|   const double c  =  0.39894228; | ||||
| 
 | ||||
|   t = 1. / (1. + p * FABS(x)); | ||||
|   series = (1. - c * exp( -x * x / 2.) * t * | ||||
|       (t*(t*(t*(t*b5 + b4) + b3) + b2) + b1)); | ||||
| 
 | ||||
|   return (x > 0.) ? 1. - series : series; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Lower tail quantile for standard disribution function. | ||||
|  * | ||||
|  * This function returns an approximation of the inverse cumulative | ||||
|  * standard normal distribution system. I.e., given P, it returns | ||||
|  * an approximation to the X satisfying P = Pr{Z <= X} Where Z is a | ||||
|  * random variable from the standard normal distribution. | ||||
|  * | ||||
|  * The algorithm uses a minimax approximation by rational functions and | ||||
|  * the result has a relative error whose absolute value is less than | ||||
|  * 1.15e-9. | ||||
|  */ | ||||
| /* Coefficients in rational approximations. */ | ||||
| static const double a[] = { | ||||
|   -3.969683028665376e+01, | ||||
|   2.209460984245205e+02, | ||||
|   -2.759285104469687e+02, | ||||
|   1.383577518672690e+02, | ||||
|   -3.066479806614716e+01, | ||||
|   2.506628277459239e+00 | ||||
| }; | ||||
| 
 | ||||
| static const double b[] = { | ||||
|   -5.447609879822406e+01, | ||||
|   1.615858368580409e+02, | ||||
|   -1.556989798598866e+02, | ||||
|   6.680131188771972e+01, | ||||
|   -1.328068155288572e+01 | ||||
| }; | ||||
| 
 | ||||
| static const double c[] = { | ||||
|   -7.784894002430293e-03, | ||||
|   -3.223964580411365e-01, | ||||
|   -2.400758277161838e+00, | ||||
|   -2.549732539343734e+00, | ||||
|   4.374664141464968e+00, | ||||
|   2.938163982698783e+00 | ||||
| }; | ||||
| 
 | ||||
| static const double d[] = { | ||||
|   7.784695709041462e-03, | ||||
|   3.224671290700398e-01, | ||||
|   2.445134137142996e+00, | ||||
|   3.754408661907416e+00 | ||||
| }; | ||||
| 
 | ||||
| #define LOW   0.02425 | ||||
| #define HIGH  0.97575 | ||||
| 
 | ||||
| double NormalInverse( double p ) { | ||||
|   double x, e, u, q, r; | ||||
| 
 | ||||
|   /* Check for errors. */ | ||||
|   errno = 0; | ||||
|   if((p < 0) || (p > 1)) { | ||||
|     errno = EDOM; | ||||
|     return 0.; | ||||
|   } | ||||
|   else if(p == 0.) { | ||||
|     errno = ERANGE; | ||||
|     return -HUGE_VAL /* minus "infinity". */; | ||||
|   } | ||||
|   else if(p == 1.) { | ||||
|     errno = ERANGE; | ||||
|     return HUGE_VAL /* "infinity". */; | ||||
|   } | ||||
|   /* Use different aproximations for different parts. */ | ||||
|   else if(p < LOW) { | ||||
|     /* Rational approximation for lower region. */ | ||||
|     q = sqrt(-2*log(p)); | ||||
|     x = (((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) / | ||||
|        ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1); | ||||
|   } | ||||
|   else if(p > HIGH) { | ||||
|     /* Rational approximation for upper region. */ | ||||
|     q  = sqrt(-2*log(1-p)); | ||||
|     x = -(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) / | ||||
|        ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1); | ||||
|   } | ||||
|   else { | ||||
|     /* Rational approximation for central region. */ | ||||
|     q = p - 0.5; | ||||
|     r = q*q; | ||||
|     x = (((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q / | ||||
|        (((((b[0]*r+b[1])*r+b[2])*r+b[3])*r+b[4])*r+1); | ||||
|   } | ||||
| 
 | ||||
|   /* Full machine precision. */ | ||||
|   e = 0.5 * erfc(-x / M_SQRT2) - p; | ||||
|   u = e * 2.5066282746310002 /* sqrt(2*pi) */ * exp((x*x)/2); | ||||
|   x =  x - u/(1 + x*u/2); | ||||
| 
 | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -4,7 +4,14 @@ | ||||
| #define RNG_SANE(L,H)  ((int)L + (int)((double)(H-L+1) * randfp())) /* L <= RNG <= H */ | ||||
| #define RNGF()  (randfp()) /* 0. <= RNGF <= 1. */ | ||||
| 
 | ||||
| /* Init. */ | ||||
| void rng_init(void); | ||||
| 
 | ||||
| /* Random functions. */ | ||||
| unsigned int randint(void); | ||||
| double randfp(void); | ||||
| 
 | ||||
| /* Probability functions. */ | ||||
| double Normal(double x); | ||||
| double NormalInverse(double p); | ||||
| 
 | ||||
|  | ||||
| @ -426,11 +426,11 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* | ||||
|         vect_cset(&v, x, y); | ||||
| 
 | ||||
|         rdir = VANGLE(v); | ||||
|         rdir += RNG(-outfit->u.blt.accuracy/2., | ||||
|             outfit->u.blt.accuracy/2.)/180.*M_PI; | ||||
|       } else /* Fire straight. */ | ||||
|         rdir = dir + RNG(-outfit->u.blt.accuracy/2., | ||||
|             outfit->u.blt.accuracy/2.)/180.*M_PI; | ||||
|         rdir = dir; | ||||
| 
 | ||||
|       rdir += NormalInverse(RNGF()*0.9 + 0.05) /* Get rid of extreme values. */ | ||||
|         * outfit->u.blt.accuracy/2. * 1./180.0*M_PI; | ||||
| 
 | ||||
|     if((rdir > 2.*M_PI) || (rdir < 0.)) rdir = fmod(rdir, 2.*M_PI); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Allanis
						Allanis