📄 itknormalvariategenerator.cxx
字号:
/*=========================================================================
Program: Insight Segmentation & Registration Toolkit
Module: $RCSfile: itkNormalVariateGenerator.cxx,v $
Language: C++
Date: $Date: 2006-03-19 04:37:20 $
Version: $Revision: 1.15 $
Copyright (c) Insight Software Consortium. All rights reserved.
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include <vnl/vnl_math.h>
#include <math.h>
#include "itkNormalVariateGenerator.h"
namespace itk {
namespace Statistics {
NormalVariateGenerator::NormalVariateGenerator()
{
Scale = ((double) 30000000.0) ;
Rscale = ((double) (1.0 / Scale)) ;
Rcons = ((double) (1.0 / (2.0 * 1024.0 * 1024.0 * 1024.0))) ;
ELEN = 7 ; /* LEN must be 2 ** ELEN */
LEN = 128 ;
LMASK = (4 * (LEN-1)) ;
TLEN = (8*LEN) ;
vec1 = new int[TLEN] ;
gausssave = 0 ;
this->Initialize(0) ;
}
NormalVariateGenerator::~NormalVariateGenerator()
{
delete[] vec1 ;
}
void NormalVariateGenerator::PrintSelf(std::ostream& os, Indent indent) const
{
Superclass::PrintSelf(os, indent) ;
os << indent << "Scale: " << Scale << std::endl ;
os << indent << "Rscale: " << Rscale << std::endl ;
os << indent << "Rcons: " << Rcons << std::endl ;
os << indent << "ELEN: " << ELEN << std::endl ;
os << indent << "LEN: " << LEN << std::endl ;
os << indent << "LMASK: " << LMASK << std::endl ;
os << indent << "TLEN: " << TLEN << std::endl ;
os << indent << "gaussfaze: " << gaussfaze << std::endl ;
os << indent << "gausssave: " << gausssave << std::endl ;
os << indent << "GScale: " << GScale << std::endl ;
os << indent << "vec1: " << vec1 << std::endl ;
os << indent << "nslew: " << nslew << std::endl ;
os << indent << "irs: " << irs << std::endl ;
os << indent << "lseed: " << lseed << std::endl ;
os << indent << "chic1: " << chic1 << std::endl ;
os << indent << "chic2: " << chic2 << std::endl ;
os << indent << "actualRSD: " << actualRSD << std::endl ;
}
void NormalVariateGenerator::Initialize(int randomSeed)
{
// m_Random Seed was originally getpid()
double fake ;
lseed = randomSeed ;
irs = randomSeed ;
gaussfaze = 1 ;
nslew = 0 ;
GScale = Rscale ;
// At one stage, we need to generate a random variable Z such that
// (TLEN * Z*Z) has a Chi-squared-TLEN density. Now, a var with
// an approximate Chi-sq-K distn can be got as
// 0.5 * (C + A*n)**2 where n has unit Normal distn,
// A = (1 + 1 / (8K)), C*C = 2K - A*A (For large K)
// So we form Z as (sqrt (1 / 2TLEN)) * (C + A*n)
// or:
// Z = (sqrt (1/2TLEN)) * A * (B + n)
// where:
// B = C / A.
// We set chic1 = A * vcl_sqrt(0.5 / TLEN), chic2 = B
fake = 1.0 + 0.125 / TLEN; // This is A
chic2 = vcl_sqrt(2.0 * TLEN - fake*fake) / fake;
chic1 = fake * vcl_sqrt(0.5 / TLEN);
actualRSD = 0.0 ;
return;
}
double NormalVariateGenerator::GetVariate()
{
if (--gaussfaze)
return GScale * gausssave[gaussfaze] ;
else
return FastNorm() ;
}
/* ----------------------------------------------------- */
double NormalVariateGenerator::FastNorm(void)
{
int i;
int inc = 0;
int skew;
int stride;
int mask = 0;
int p;
int q;
int r;
int s;
int t;
int *pa = 0;
int *pb = 0;
int *pc = 0;
int *pd = 0;
int *pe;
int *p0 = 0;
int mtype;
int stype;
double ts;
double tr;
double tx;
double ty;
double tz;
/* See if time to make a new set of 'original' deviates */
/* or at least to correct for a drift in sum-of-squares */
if (! (nslew & 0xFF)) goto renormalize;
startpass:
/* Count passes */
nslew ++;
/* Reset index into Saved values */
gaussfaze = TLEN - 1; /* We will steal the last one */
/* Update pseudo-random and use to choose type of rotation */
lseed = 69069 * lseed + 33331;
irs = (irs <= 0) ? ((irs << 1) ^ 333556017):(irs << 1);
t = irs + lseed;
if (t < 0) t = ~t;
/* This gives us 31 random bits in t */
/* We need ELEN to fix initial index into LEN, ELEN-1 to fix an odd
stride, 2 to fix matrix type and maybe 1 for scantype, making
2*ELEN + 2 in all, and leaving 29 - 2*ELEN unused
*/
t = t >> (29 - 2*ELEN); /* Discard unwanted digits */
skew = (LEN-1) & t; t = t >> ELEN;
skew = 4 * skew; /* To give a word index to group of 4 */
stride = (LEN/2 -1 ) & t; t = t >> (ELEN-1);
stride = 8 * stride + 4; /* To give an odd num of 4-groups */
mtype = t & 3;
/* Leaves a bit for stype, but not currently used */
/* Use last bits of nslew to determine scanning pattern */
stype = nslew & 3;
switch (stype) {
case 0: /* From consecutive in top to scattered in bot */
inc = 1;
mask = LMASK;
pa = vec1; pb = pa + LEN; pc = pb + LEN; pd = pc + LEN;
p0 = vec1 + 4 * LEN;
goto scanset;
case 1: /* From consec in bot to scatt in top */
inc = 1;
mask = LMASK;
pa = vec1 + 4 * LEN; pb = pa + LEN; pc = pb + LEN; pd = pc + LEN;
p0 = vec1;
goto scanset;
case 2: /* From consec in even to scatt in odd */
inc = 2;
mask = 2*LMASK; skew *= 2; stride *= 2;
pa = vec1 + 1; pb = pa + 2*LEN; pc = pb + 2*LEN; pd = pc + 2*LEN;
p0 = vec1;
goto scanset;
case 3: /* From consec in odd to scatt in even */
inc = 2;
mask = 2*LMASK; skew *= 2; stride *= 2;
pa = vec1; pb = pa + 2*LEN; pc = pb + 2*LEN; pd = pc + 2*LEN;
p0 = vec1 + 1;
goto scanset;
} /* End of scan pattern cases */
scanset:
gausssave = vec1;
/* Set loop count */
i = LEN;
/* Use mtype to select matrix */
switch (mtype) {
case 0: goto matrix0;
case 1: goto matrix1;
case 2: goto matrix2;
case 3: goto matrix3;
}
matrix0:
pa += (inc * (LEN-1));
mpass0:
skew = (skew + stride) & mask;
pe = p0 + skew;
p = -*pa; q = -*pb; r = *pc; s = *pd;
t = (p + q + r + s) >> 1;
p = t - p; q = t - q; r = t - r; s = t - s;
/* Have new values in p,q,r,s. Place and save replaced vals */
t = -*pe; *pe = p; pe += inc;
p = *pe; *pe = q; pe += inc;
q = -*pe; *pe = r; pe += inc;
r = *pe; *pe = s;
/* Have vals in p,q,r,t */
s = (p + q + r + t) >> 1;
*pa = s - p; pa -= inc;
*pb = s - q; pb += inc;
*pc = s - r; pc += inc;
*pd = s - t; pd += inc;
if (--i) goto mpass0;
goto endpass;
matrix1:
pb += (inc * (LEN-1));
mpass1:
skew = (skew + stride) & mask;
pe = p0 + skew;
p = -*pa; q = *pb; r = *pc; s = -*pd;
t = (p + q + r + s) >> 1;
p = t - p; q = t - q; r = t - r; s = t - s;
/* Have new values in p,q,r,s. Place and save replaced vals */
t = *pe; *pe = p; pe += inc;
p = -*pe; *pe = q; pe += inc;
q = -*pe; *pe = r; pe += inc;
r = *pe; *pe = s;
/* Have vals in p,q,r,t */
s = (p + q + r + t) >> 1;
*pa = s - p; pa += inc;
*pb = s - t; pb -= inc;
*pc = s - q; pc += inc;
*pd = s - r; pd += inc;
if (--i) goto mpass1;
goto endpass;
matrix2:
pc += (inc * (LEN-1));
mpass2:
skew = (skew + stride) & mask;
pe = p0 + skew;
p = *pa; q = -*pb; r = *pc; s = -*pd;
t = (p + q + r + s) >> 1;
p = t - p; q = t - q; r = t - r; s = t - s;
/* Have new values in p,q,r,s. Place and save replaced vals */
t = *pe; *pe = p; pe += inc;
p = *pe; *pe = q; pe += inc;
q = -*pe; *pe = r; pe += inc;
r = -*pe; *pe = s;
/* Have vals in p,q,r,t */
s = (p + q + r + t) >> 1;
*pa = s - r; pa += inc;
*pb = s - p; pb += inc;
*pc = s - q; pc -= inc;
*pd = s - t; pd += inc;
if (--i) goto mpass2;
goto endpass;
matrix3:
pd += (inc * (LEN-1));
mpass3:
skew = (skew + stride) & mask;
pe = p0 + skew;
p = *pa; q = *pb; r = -*pc; s = -*pd;
t = (p + q + r + s) >> 1;
p = t - p; q = t - q; r = t - r; s = t - s;
/* Have new values in p,q,r,s. Place and save replaced vals */
t = -*pe; *pe = p; pe += inc;
p = *pe; *pe = q; pe += inc;
q = *pe; *pe = r; pe += inc;
r = -*pe; *pe = s;
/* Have vals in p,q,r,t */
s = (p + q + r + t) >> 1;
*pa = s - q; pa += inc;
*pb = s - r; pb += inc;
*pc = s - t; pc += inc;
*pd = s - p; pd -= inc;
if (--i) goto mpass3;
goto endpass;
endpass:
/* Choose a value for GScale which will make the sum-of-squares have
the variance of Chi-Sq (TLEN), i.e., 2*TLEN. Choose a value from
Chi-Sq (TLEN) using the method descibed in initnorm.
The Normal variate is obtained from gausssave[TLEN-1], which is
not used by the caller.
*/
ts = chic1 * (chic2 + GScale * vec1 [TLEN-1]);
/* TLEN * ts * ts has ChiSq (TLEN) distribution */
GScale = Rscale * ts * actualRSD;
return (GScale * vec1[0]);
renormalize:
if (nslew & 0xFFFF) goto recalcsumsq;
/* Here, replace the whole pool with conventional Normal variates */
ts = 0.0;
p = 0;
nextpair:
lseed = 69069 * lseed + 33331;
irs = (irs <= 0) ? ((irs << 1) ^ 333556017):(irs << 1);
r = irs + lseed;
tx = Rcons * r;
lseed = 69069 * lseed + 33331;
irs = (irs <= 0) ? ((irs << 1) ^ 333556017):(irs << 1);
r = irs + lseed;
ty = Rcons * r;
tr = tx * tx + ty * ty;
if ((tr > 1.0) || (tr < 0.1)) goto nextpair;
lseed = 69069 * lseed + 33331;
irs = (irs <= 0) ? ((irs << 1) ^ 333556017):(irs << 1);
r = irs + lseed;
if (r < 0) r = ~r;
tz = -2.0 * vcl_log((r + 0.5) * Rcons); /* Sum of squares */
ts += tz;
tz = vcl_sqrt(tz / tr );
vec1 [p++] = (int) (Scale * tx * tz) ;
vec1 [p++] = (int) (Scale * ty * tz) ;
if (p < TLEN) goto nextpair;
/* Horrid, but good enough */
/* Calc correction factor to make sum of squares = TLEN */
ts = TLEN / ts; /* Should be close to 1.0 */
tr = vcl_sqrt(ts);
for (p = 0; p < TLEN; p++) {
tx = vec1 [p] * tr;
vec1 [p] = (int) ((tx < 0.0) ? (tx - 0.5) : (tx + 0.5)) ;
}
recalcsumsq:
/* Calculate actual sum of squares for correction */
ts = 0.0;
for (p = 0; p < TLEN; p++) {
tx = vec1[p];
ts += (tx * tx);
}
/* Now ts should be Scale*Scale*TLEN or thereabouts */
ts = vcl_sqrt(ts / (Scale * Scale * TLEN));
actualRSD = 1.0 / ts; /* Reciprocal of actual Standard Devtn */
goto startpass;
}
} // end of name space Statistics
} // end of name space itk
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -