# XT_STAT -- Compute statistics from a sample.
#
# The sample array will be sorted.

define	NMIN	10	# Minimum number of pixels for mode calculation
define	ZSTEP	0.01	# Step size for search for mode
define	ZBIN	0.1	# Bin size for mode.

$for (sird)
procedure xt_stat$t (sample, nsample, frac, mean, sigma, median, mode)

PIXEL	sample[nsample]			#I Sample
int	nsample				#I Number of sample pixels
real	frac				#I Fraction of data to use
$if (datatype == d)
double	mean, sigma, median, mode	#O Statistics
$else
real	mean, sigma, median, mode	#O Statistics
$endif

int	i, j, k, nmax
$if (datatype == d)
double	z1, z2, zstep, zbin
bool	fp_equald()
$else
real	z1, z2, zstep, zbin
bool	fp_equalr()
$endif

begin
	# Sort the sample.
	call asrt$t (sample, sample, nsample)

	# Set fraction to use.
	i = max (1, 1 + nsample * (1. - frac) / 2.)
	j = min (nsample, 1 + nsample * (1. + frac) / 2.)
	z1 = sample[i]
	z2 = sample[j]

	# Compute the mean and sigma.
	call aavg$t (sample[i], j-i+1, mean, sigma)

	# Compute the median.
	median =  sample[nsample/2]

	z1 = median - 2 * sigma
	if (z1 < sample[1])
	    i = 1
	else {
	    k = i
	    do i = k, 2, -1 {
		if (sample[i] <= z1)
		    break
	    }
	}
	z1 = sample[i]

	z2 = median + 2 * sigma
	if (z2 > sample[nsample])
	    i = nsample
	else {
	    k = j
	    do j = k, nsample-1 {
		if (sample[j] >= z1)
		    break
	    }
	}
	z2 = sample[j]

	# Compute the mode.

	if (nsample < NMIN)
	    mode = median

$if (datatype == d)
	else if (fp_equald (z1, z2))
$else
	else if (fp_equalr (z1, z2))
$endif
	    mode = z1

	else {
	    zstep = ZSTEP * sigma
	    zbin = ZBIN * sigma
	    $if (datatype == sil)
	    zstep = max (1., zstep)
	    zbin = max (1., zbin)
	    $endif

	    z1 = z1 - zstep
	    k = i
	    nmax = 0
	    repeat {
		z1 = z1 + zstep
		z2 = z1 + zbin
		for (; i < j && sample[i] < z1; i=i+1)
		    ;
		for (; k < j && sample[k] < z2; k=k+1)
		    ;
		if (k - i > nmax) {
		    nmax = k - i
		    mode = sample[(i+k)/2]
		}
	    } until (k >= j)
	}
end
$endfor
