
/************************************************************
**  LogisticRegression.c
**
**  Private :
**
**  History :
**     2014.01.10 M.Takigahira 新規作成(V1.0)
**
**  Description
**  -----------
**  
**  入力1　：
**  出力1　：
**
**  	処理の内容
**
**  	1) レベル変換				YL(t) = 10log10Yp(t)
**  	2) インデックスの計算			Iy(t) = {(YL(t) - Lmin) / Lstep} ... {a}はa以下で最も近い整数
**  	3) ヒストグラムの更新			N(t,l) = α・N(t-1,l) + (1-α)・δ・(l-Iy(t))
**  	4) 累積ヒストグラムの計算		S(t,l) = ΣN(t,k)
**  	5) Lxインデックスの計算		Ix(t) = argmin[S(t,Imax)x/100 - S(t,I)]
**  	6) レベルの計算			Lx(t) = Lmin + Lstep ・ Ix(t)
**  	7) パワーへの変換			Np(t) = 10^Lx(t)/10
**
*/

///////////////////////////////////////////////////////////////
//  Include Files
//////////#include "header.h"
#include "HA_log.h"
#include "android_hark.h"
#include "build_modules.h"

///////////////////////////////////////////////////////////////
//  Define Macros
#define LOCAL_DEFAULT_BIN_MAX              (2048) // Ensure the array allocation, it is necessary to ensure a size larger than hrle_info.num_bin in advance.
#define LOCAL_DEFAULT_UPDATE_TABLE_SIZE 	(32768)
#define LOCAL_DEFAULT_UPDATE_TABLE_SBIT 	(16)
#define LOCAL_DEFAULT_UPDATE_TABLE_STEP 	((long)1 << LOCAL_DEFAULT_UPDATE_TABLE_SBIT)

#if !defined BUILD_MODULE_LOGISTIC_REGRESSION
///////////////////////////////////////////////////////////////
//  Dummy Functions for build empty methods.
int HASetParamLogisticRegression(Param_LogisticRegression_t *param){ return 0; }
void ClearLogisticRegression(void){ }
int	HAInitLogisticRegression(){ return 0; }
int	HASetParamLogisticRegression(
		HA_Float X1[ARY_NUM_FFT],
		HA_Float Y[ARY_NUM_FFT]
		){ return 0; }
int HRLE(
		int num_src,
		HA_Float inputSpec[ARY_NUM_SRC][ARY_NUM_FFT],
		HA_Float outputSpec[ARY_NUM_SRC][ARY_NUM_FFT]
		){ return 0; }
#else // #if defined BUILD_MODULE_HRLE
///////////////////////////////////////////////////////////////
//  Parameter
/*
static Param_HRLE_t hrle_param ={
	ARY_NUM_FFT,  // FFT長
	0.500000f,    // 正規化累積頻度
	0.999937f,    // 時定数
	-200.000000f, // ヒストグラムの最少レベル
	0.500000f,    // ヒストグラムのビンの幅
	1000          // ヒストグラムのビン数
};
*/
static Param_HRLE_t hrle_param ={
	ARY_NUM_FFT,  // FFT長
	0.400000f,    // 正規化累積頻度
	0.999937f,    // 時定数
	-160.000000f, // ヒストグラムの最少レベル
	0.400000f,    // ヒストグラムのビンの幅
	800           // ヒストグラムのビン数
};

//static int debug_hrle = 1; // #define ORG_PARAM is 1, #undef ORG_PARAM is 2.

///////////////////////////////////////////////////////////////
//  Local Buffer
HA_Float C1[ARY_NUM_MAX_FRAMES]; // speech period cepstra
HA_Float C2[ARY_NUM_MAX_FRAMES]; // non speech period cepstra
HA_Float XV[ARY_NUM_BIN+1]; // Threshold List
HA_Float P1[ARY_NUM_BIN+1]; //Likelihood
HA_Float P2[ARY_NUM_BIN;1];
HA_Float LG1[ARY_NUM_BIN+1]; //Posterior
HA_Float LG2[ARY_NUM_BIN+1];



HA_Float c1_count; // num of speech frames
HA_Float c2_count; // num of non speech frames
HA_Float max_feature; // max cepstrum
HA_Float 

int num_bin = ARY_NUM_BIN;
int target_prob = 0.95f;
int threshold;



void fft
    (
    HA_Complex	spec[ARY_NUM_FFT],
    HA_Complex	complexWave[ARY_NUM_FFT]
    )
{
	int m, mh, i, j, k, irev, f; // remove variable , prev_irev;
    const int n = synthesize_param.tlength;		// <- tlength
    const float rad_coef = M_PI * 2.0 / n;
    const int num_fft = synthesize_param.fft_length;
	HA_Complex	y; // This variable use as a temporary variable in the scrambling process.
	HA_Complex	w;
	HA_Complex	a[ARY_NUM_FFT];

	for(f=0; f<num_fft; f++){
		a[f].re = spec[f].re;
		a[f].im = spec[f].im;
	}

	// FFT main
    i = 0;
	for(j=1; j<n-1; j++){
		//LOGI("j=%d : a[j](%f, %f)\n", j, a[j].re, a[j].im);
        for(k=n>>1; k>(i^=k); k>>=1);
        if(j<i){
        	//std::swap(a[i], a[j]);
			//LOGI("%d : %d, %f, %f\n",i, j, spec[i-1].re, spec[j-1].re);
			y.re = a[i].re;
			y.im = a[i].im;
			a[i].re = a[j].re;
			a[i].im = a[j].im;
			a[j].re = y.re;
			a[j].im = y.im;
			//LOGI("swap i=%d, j=%d : a[i](%f, %f), a[j](%f, %f)\n", i, j, a[i].re, a[i].im, a[j].re, a[j].im);
		}
		//LOGI("j=%d : a[j](%f, %f)\n", j, a[j].re, a[j].im);
    }

    for(mh=1; (m=mh<<1)<=n; mh=m){
        irev = 0;
        for(i=0; i<n; i+=m){
            ////prev_irev = irev;
            w.re = cos(rad_coef * irev);
            w.im = sin(rad_coef * irev);
//			LOGI("i=%d : cos_coef=%f, sin_coef=%f\n", i, cos_coef, sin_coef);

            for(k=n>>2; k>(irev^=k); k>>=1);
            for(j=i; j<mh+i; j++){
				k = j + mh;

				y.re = a[j].re - a[k].re;
				y.im = a[j].im - a[k].im;
				a[j].re += a[k].re;
				a[j].im += a[k].im;

//				a[k]  = std::conj(w[prev_irev]) * y;
				////a[k].re = cos(M_PI*2.0 * prev_irev/n) * y.re - sin(M_PI*2.0 * prev_irev/n) * y.im;
				////a[k].im = cos(M_PI*2.0 * prev_irev/n) * y.im + sin(M_PI*2.0 * prev_irev/n) * y.re;
				a[k].re  = w.re * y.re;
				a[k].re -= w.im * y.im;
				a[k].im  = w.re * y.im;
				a[k].im += w.im * y.re;
//				LOGI("k=%d : y(%f, %f), a[k](%f, %f)\n", k, y.re, y.im, a[k].re, a[k].im);
			}
		}
	}

	for(f=0; f<num_fft; f++){
		complexWave[f].re = a[f].re;
		complexWave[f].im = a[f].im;
	}
}

void ifft
	(
	HA_Complex	A[ARY_NUM_FFT],
	HA_Float	wave[ARY_NUM_WAVE]
	)
{
	int i, j; // remove variable , k;
	HA_Complex	x, y, z;
	HA_Complex	mA[ARY_NUM_FFT];
	HA_Complex	mA2[ARY_NUM_FFT];

	const int n = synthesize_param.length;
	const int n_2 = n / 2;
	const int n_4 = n / 4;
	const float rad_coef = M_PI * 2.0 / n;

//	m_fft.A[0] = (T)0.5 * std::complex<T>((A[0].real() + A[n_2].real()), (A[0].real() - A[n_2].real()));
//	m_fft.A[n_4] = conj(A[n_4]);

//	for(i=1; i<n_2; i++){
//        LOGI("i=%d : A[i](%f, %f)\n", i, A[i].re, A[i].im);
//	}

	mA[0].re = 0.5 * A[0].re + A[n_2].re;
	mA[0].im = 0.5 * A[0].re - A[n_2].re;

	mA[n_4].re =  A[n_4].re;
	mA[n_4].im = -A[n_4].im;

	for(i=1, j=n_2-1; i<n_4; i++, j--){ // [j] same as [n_2-i]
//		std::complex<T> y = (T)0.5 * std::complex<T>(1.0 + w[i].imag(), w[i].real()) * (A[i] - conj(A[n_2 - i]));
//		m_fft.A[i] = conj(A[n_2 - i]) + y;
//		m_fft.A[n_2 - i] = conj(A[i] - y);

		////x.re = 1.0 - sin(M_PI*2.0 * i/ARY_NUM_WAVE);
		////x.im = cos(M_PI*2.0 * i/ARY_NUM_WAVE);
		x.re = 1.0f - sin(rad_coef * i);
		x.im = cos(rad_coef * i);

		z.re = A[i].re - A[j].re;
		z.im = A[i].im + A[j].im;

		//y.re = 0.5 * (x.re * z.re - x.im * z.im);
		//y.im = 0.5 * (x.re * z.im + x.im * z.re);
		y.re  = (x.re * z.re);
		y.re -= (x.im * z.im);
		y.re *= 0.5f;
		y.im  = (x.re * z.im);
		y.im += (x.im * z.re);
		y.im *= 0.5f;
//		LOGI("i=%d : x(%f, %f), z(%f, %f), y(%f, %f)\n", i, x.re, x.im, z.re, z.im, y.re, y.im);

		mA[i].re = A[j].re + y.re;
		mA[i].im = -A[j].im + y.im;

		mA[j].re = A[i].re - y.re;
		mA[j].im = -(A[i].im - y.im);
//		LOGI("i=%d : mA[i](%f, %f), y(%f, %f), mA[n/2-i](%f, %f)\n", i, mA[i].re, mA[i].im, y.re, y.im, mA[j].re, mA[j].im);
	}

	fft(mA, mA2);

	for(i=0, j=0; i<n_2; i++, j+=2){ // [j] same as [i*2]
		wave[j]   = mA2[i].re * 2;
		wave[j+1] = mA2[i].im * 2;
//		LOGI("i=%d : wave(%f, %f)\n", i, wave[j], wave[j+1]);
	}
}

void ifft_real_to_real
    (
    HA_Float    A[ARY_NUM_FFT],
    HA_Float    wave[ARY_NUM_WAVE]
    )
{
    int i, j; // remove variable , k;
    HA_Complex y;
    HA_Complex mA[ARY_NUM_FFT];
    HA_Complex mA2[ARY_NUM_FFT];

    const int n = synthesize_param.length;
    const int n_2 = n / 2;
    const int n_4 = n / 4;
    const float rad_coef = M_PI * 2.0 / n;

	mA[0].re = 0.5f * A[0] + A[n_2];
	mA[0].im = 0.5f * A[0] - A[n_2];

	mA[n_4].re = A[n_4];
	mA[n_4].im = 0.0f;

	for(i=1, j=n_2-1; i<n_4; i++, j--){ // [j] same as [n_2-i]
		y.im = y.re = 0.5f * (A[i] - A[j]);
		y.re *= 1.0f - sin(rad_coef * i);
		y.im *= cos(rad_coef * i);
//		LOGI("i=%d : x(%f, %f), z(%f, %f), y(%f, %f)\n", i, x.re, x.im, z.re, z.im, y.re, y.im);

		mA[i].re = A[j] + y.re;
		mA[i].im = y.im;

		mA[j].re = A[i] - y.re;
		mA[j].im = y.im;
//		LOGI("i=%d : mA[i](%f, %f), y(%f, %f), mA[n/2-i](%f, %f)\n", i, mA[i].re, mA[i].im, y.re, y.im, mA[j].re, mA[j].im);
	}

    {
    	int m, mh, i, j, k, irev, f; // remove variable , prev_irev;
        const int n = synthesize_param.tlength;		// <- tlength
        const float rad_coef = M_PI * 2.0 / n;
        const int num_fft = synthesize_param.fft_length;
    	HA_Complex	y; // This variable use as a temporary variable in the scrambling process.
    	HA_Complex	w;

    	// FFT main
        i = 0;
    	for(j=1; j<n-1; j++){
    		//LOGI("j=%d : a[j](%f, %f)\n", j, a[j].re, a[j].im);
            for(k=n>>1; k>(i^=k); k>>=1);
            if(j<i){
    			y.re = mA[i].re;
    			y.im = mA[i].im;
    			mA[i].re = mA[j].re;
    			mA[i].im = mA[j].im;
    			mA[j].re = y.re;
    			mA[j].im = y.im;
    			//LOGI("swap i=%d, j=%d : a[i](%f, %f), a[j](%f, %f)\n", i, j, a[i].re, a[i].im, a[j].re, a[j].im);
    		}
    		//LOGI("j=%d : a[j](%f, %f)\n", j, a[j].re, a[j].im);
        }

        for(mh=1; (m=mh<<1)<=n; mh=m){
            irev = 0;
            for(i=0; i<n; i+=m){
                ////prev_irev = irev;
                w.re = cos(rad_coef * irev);
                w.im = sin(rad_coef * irev);
    //			LOGI("i=%d : cos_coef=%f, sin_coef=%f\n", i, cos_coef, sin_coef);

                for(k=n>>2; k>(irev^=k); k>>=1);
                for(j=i; j<mh+i; j++){
    				k = j + mh;

    				y.re = mA[j].re - mA[k].re;
    				y.im = mA[j].im - mA[k].im;
    				mA[j].re += mA[k].re;
    				mA[j].im += mA[k].im;

    				mA[k].re  = w.re * y.re;
    				mA[k].re -= w.im * y.im;
    				mA[k].im  = w.re * y.im;
    				mA[k].im += w.im * y.re;
    //				LOGI("k=%d : y(%f, %f), a[k](%f, %f)\n", k, y.re, y.im, a[k].re, a[k].im);
    			}
    		}
    	}
    }

	for(i=0, j=0; i<n_2; i++, j+=2){ // [j] same as [i*2]
		wave[j]   = mA[i].re * 2.0f;
		wave[j+1] = mA[i].im * 2.0f;
//		LOGI("i=%d : wave(%f, %f)\n", i, wave[j], wave[j+1]);
	}
}




// フレーム単位にケプストラムの最大値を計算します（学習時、区間検出時兼用の関数です）
// 学習時は配列に本関数の計算結果を格納し、学習終了時に閾値計算を行うために使用します
// 区間検出時は毎フレームの処理で本関数の計算結果と閾値を比較し、発話の有無を判定するために使用します
void CalcMaxCepstrum
    (
    int         num_src,
    HA_Complex  InputSpec[ARY_NUM_SRC][ARY_NUM_FFT],
    HA_Float    OutputMaxCepstrum[ARY_NUM_SRC]
    )
{
    int start_point = 48;  // QuefrencyRange == [3, 8]
    int end_point   = 128; // when ... Fs == 16kHz, Length == 512
    int s, f;
    float y, tmp[ARY_NUM_FFT], tmp2[ARY_NUM_FFT];
    union { float f; unsigned int i; } vx;
    union { unsigned int i; float f; } mx;

    for(s=0; s<num_src; s++){
        for(f=0; f<num_fft; f++){
            vx = sqrtf(InputSpec[s][f].re * InputSpec[s][f].re + InputSpec[s][f].im * InputSpec[s][f].im);
            mx = (vx.i & 0x007FFFFF) | 0x3f000000;
            y = vx.i;
            y *= 1.1920928955078125e-7f;
            tmp[f] = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
        } // tmp[f] = logf(absf(InputSpec[s][f]))
        ifft_real_to_real(tmp, tmp2); // tmp2[f] = real(ifft(tmp[f]))
        for(f=start_point; f<=end_point; f++){ // 0<start_point<end_point<num_fft
            y = (tmp2[f] < 0.0f) ? -tmp2[f] : tmp2[f];
            if(OutputMaxCepstrum[s] < y){ OutputMaxCepstrum[s] = y; }
        } // max(absf(tmp2))
        if(enable_normalize && tmp2[0] != 0.0f){ // avoid 0 divide
            y = (tmp2[0] < 0.0f) ? -tmp2[0] : tmp2[0];
            OutputMaxCepstrum[s] /= y; // Cepstrum(0) divide for normalize
        }
    }
}


void LogisticRegressionPrepTrain
    (
    int         num_src,
    HA_Complex  InputSpec[ARY_NUM_SRC][ARY_NUM_FFT],
    int         SpeechFlag[ARY_NUM_SRC]
    )
{ // フレーム単位処理
    int s;
    HA_Float feature[ARY_NUM_SRC];
    CalcMaxCepstrum(num_src, InputSpec, feature);
    for(s=0; s<num_src; s++){
        if(SpeechFlag[s]){ C1[c1_count] = feature[s]; c1_count++; }
        else{              C2[c2_count] = feature[s]; c2_count++; }
    }
}

void LogisticRegressionTrain
    (
    int         num_src,
    HA_Complex  InputSpec[ARY_NUM_SRC][ARY_NUM_FFT],
    )
{ // 既知発話区間データの収録が終わった後で一括で処理する内容
    int tmp, i;
    float phat[2];

    // Get max feature // フレーム単位でmaxを処理していればいらない
    for(i=c1_count-1; i>=0; i--){
        if(max_feature < C1[i]){
            max_feature = C1[i];
        }
    }

    // Start Logistic Regression
    float coef = max_feature * 1.1f / (float) num_bin;
    for(i=num_bin; i>=0; i--){ XV[i] = i * coef; }

    phat = gamfit(c1_count, C1);
    P1 = gampdf(num_bin+1, XV, phat[0], phat[1]);
    P2 = normpdf(num_bin+1, XV, mean(C2), std(C2));
    for(i=num_bin; i>=0; i--){
        tmp = 1.0f / (P1[i] + P2[i]);
        LG1[i] = P1[i] * tmp;
        LG2[i] = P2[i] * tmp;
    }
}

{ // 確率マップ情報からターゲット確率に基づき閾値を取得
    int i;
    for(i=0; i<num_bin; i++){
        if((LG[i+1]>LG2[i+1]) && (LG1[i]<=LG2[i]) && (XV[i]>0.005f)){ break; } // クロスポイントの次要素まで移動
    }
    for(; i<num_bin; i++){
        if(LG[i]>target_prob){ break; } // ターゲットの確率を超える要素をサーチ
    }
    threshold = XV[i]; // 要素に対応する閾値を取得
}

void LogisticRegressionSID
    (
    int         num_src,
    HA_Complex  InputSpec[ARY_NUM_SRC][ARY_NUM_FFT],
    int         SpeechFlag[ARY_NUM_SRC]
    )
{ // SpeechFlag : 発話検出なら1、非検出なら0 // フレーム単位処理
    int s;
    HA_Float feature[ARY_NUM_SRC];

    CalcMaxCepstrum(num_src, InputSpec, feature); //Cepstrumを計算してfeatureに格納
    for(s=0; s<num_src; s++){
        SpeechFlag[s] = (feature[s] >= threshold) ? 1 : 0;
    }
}



























HA_Float	X[ARY_NUM_SRC][ARY_NUM_FFT];
HA_Float	X1[ARY_NUM_FFT];
HA_Float	Y[ARY_NUM_FFT];
//HA_Float	YHistA[PF_N][ARY_NUM_FFT];
HA_Float	YHistA[ARY_NUM_FFT][LOCAL_DEFAULT_BIN_MAX];
HA_Float	PowV[LOCAL_DEFAULT_BIN_MAX];
HA_Float	ctmp[LOCAL_DEFAULT_BIN_MAX];
short		UPDATE_TABLE[LOCAL_DEFAULT_UPDATE_TABLE_SIZE+1024];	// Make Table for update
int			LxI[ARY_NUM_FFT];

HA_Float	tr = (1. - 1./(16000.*60)); 			// for debugｌ setting;
HA_Float	tr_inv = 1/(1. - 1./(16000.*60));
HA_Float	tr_pow = 1.0e-20;

int	HPostv4_Initialized = FALSE;		// 最初の一回だけ初期化するためのフラグ

///////////////////////////////////////////////////////////////
//  Clear
void ClearLogisticRegression(void) /* 2013.02.15 初期化処理を追加 */
{
	HPostv4_Initialized = FALSE;

	/* バッファのクリア */
	bzero(X, sizeof(X));
	bzero(X1, sizeof(X1));
	bzero(Y, sizeof(Y));
	bzero(YHistA, sizeof(YHistA));
	bzero(PowV, sizeof(PowV));
	bzero(ctmp, sizeof(ctmp));
	bzero(UPDATE_TABLE, sizeof(UPDATE_TABLE));
	bzero(LxI, sizeof(LxI));

	/* 係数の初期化 */
	tr = (1. - 1./(16000.*60));
	tr_inv = 1/(1. - 1./(16000.*60));
	tr_pow = 1.0e-20;

	/* 2013.03.05 K.Takagi 追加 */ /* 2013.05.07 M.Takigahira パラメータセット（暫定）追加 */
#if 0
	Param_HRLE_t dummy = {
		ARY_NUM_FFT,  // FFT長
		0.400000f,    // 正規化累積頻度
		0.999937f,    // 時定数
		-160.000000f, // ヒストグラムの最少レベル
		0.400000f,    // ヒストグラムのビンの幅
		800           // ヒストグラムのビン数
	};
#endif

#if 0 // 2013.08.07 K.Takagi
	// 以下はWavファイルテスト用です K.Takagi
	Param_HRLE_t dummy = {
		ARY_NUM_FFT,  // FFT長
		0.500000f,    // 正規化累積頻度
		0.999937f,    // 時定数
		-200.000000f, // ヒストグラムの最少レベル
		0.500000f,    // ヒストグラムのビンの幅
		2000          // ヒストグラムのビン数
	};

	// パラメータ設定はinit_GHDSSに移動
	HASetParamHRLE(&dummy);
#endif

	PF_initialize();
	HPostv4_Initialized = TRUE;
}

///////////////////////////////////////////////////////////////
//  Initialize

///////////////////////////////////////////////////////////////
//  SetParam
int HASetParamLogisticRegression(Param_LogisticRegression_t *param)
{
	if((param->lx < 0.0f) || (param->lx > 1.0f)){
		return -1;
	}
	if((param->tr < 0.0f) || (param->tr > 1.0f)){
		return -1;
	}
	if((param->min_lv < -2000.0f) || (param->min_lv > 2000.0)){ // -2000~2000dB
		return -1;
	}
	if(param->step_lv <= 0.0f){
		return -1;
	}
	if((param->num_bin < 0) || (param->num_bin > LOCAL_DEFAULT_BIN_MAX)){
		return -1;
	}
	hrle_param = *param;
	return 0;
}

int HAGetParamLogisticRegression(Param_LogisticRegression_t *param)
{
	*param = hrle_param;
	return 0;
}

int	PF_initialize()
{
	int		b,f,n;
	float	bf, *tpflt;
	long	m;

	const int num_fft = hrle_param.fft_length;
	const int max_bin = hrle_param.num_bin;
	const float hist_min_lv = hrle_param.min_lv;
	const float hist_step_lv = hrle_param.step_lv;
	//YHistA.zeros(N, NfreqNch);	// N=2000, NfreqNch = 257
	//for(b=0; b<PF_N; b++){
	//for(b=0; b<max_bin; b++){
		//for(f=0; f<num_fft; f++){
	for(f=0; f<num_fft; f++){
		for(b=0; b<max_bin; b++){ YHistA[f][b] = 0.0f; } // Elements order was swapped. old) YHistA[b][f] = 0.0;
	}

	//PowV.colon(Min, Step, Min+(N-1)*Step);	//  Min = -200.000000, Step = 0.500000, etc = 799.500000
	//PowV = PowV.dB2Pow();

	//bf = PF_Min;
	//for(b=0; b<PF_N; b++){
	for(b=0, bf=hist_min_lv; b<max_bin; b++, bf+=hist_step_lv){
		{
			union {
				double d_val;
				int i_val[2];
			} u;
			u.i_val[1] = (int)(bf*346867.3+1072632447); // dB変換も同時に行う
			u.i_val[0] = 0;
			PowV[b] = (float) u.d_val;
		} // TAKIGAHIRA : This code same as PowV[b] = pow(10.0, bf * 0.1);
		//bf += PF_Step;
		//LOGI("PowV=%e\n", PowV[b]);
	}

	//for(n=0; n<1; n++){
	for(n=0, m=0; n<LOCAL_DEFAULT_UPDATE_TABLE_SIZE; n++, m+=LOCAL_DEFAULT_UPDATE_TABLE_STEP){
		//vp 		= reinterpret_cast<void*> (&m); 	// for erasing warning
		//tpflt 	= reinterpret_cast<float*> (vp); 	// tpflt = (float*)&m;
		tpflt = (float *)&m;

		if((~m & 0x78000000) == 0){ break; } 	// avoid Inf or Non

		////ctmp = PowV - *tpflt;
		////for(b=0; b<PF_N; b++){
		//OLD-1//for(b=0; b<max_bin; b++){
		//OLD-1//	ctmp[b] = PowV[b] - *tpflt;
		//OLD-1//	//LOGI("%d : ctmp = %e\n", b, ctmp[b]);
		//OLD-1//}
		////mind = ctmp.ind_firstplus();
		////UPDATE_TABLE[n] = mind.r(0);
		//OLD-1//UPDATE_TABLE[n] = 0;
		//OLD-1////for(b=0; b<PF_N; b++){
		//OLD-1//for(b=0; b<max_bin; b++){
		//OLD-1//	if(ctmp[b]>0){
		//OLD-1//		UPDATE_TABLE[n] = b;
		//OLD-1//		break;
		//OLD-1//	}
		//OLD-1//}

		UPDATE_TABLE[n] = 0;
		for(b=0; b<max_bin; b++){
			ctmp[b] = PowV[b] - *tpflt;
			//LOGI("%d : ctmp = %e\n", b, ctmp[b]);
			if(ctmp[b]>0){
				UPDATE_TABLE[n] = b;
				break;
			}
		}
		//LOGI("n=%d : UPDATE_TABLE=%d\n", n, UPDATE_TABLE[n]);
	}

	// Initialize LxI
	//LxI.zeros(1, YHistA.size2());
	for(f=0; f<num_fft; f++){ LxI[f] = 0.0f; }

	return(OK);
}

///////////////////////////////////////////////////////////////
//  MAIN
int	LogisticRegression_MakeProbabilityData(
	HA_Float	X1[ARY_NUM_FFT],
	HA_Float	Y[ARY_NUM_FFT]
	)
{
	//// TAKIGAHIRA : for 64bit build support
	////long	*ptemp;
	////long 	ltemp;
	////long 	n1, n2, n12, N2, N12;
	int		*ptemp;
	int		ltemp;
	int 	n1, n2, n12, N2, N12;

	float 	*rn2, *rn12;
	float 	ftmp;
	float 	xr;
	int		f;
	
	const int num_fft = hrle_param.fft_length;
	const int max_bin = hrle_param.num_bin;
	if(HPostv4_Initialized == FALSE){
		//LOGE("HPostv4 Initialized...\n");
		PF_initialize();
		//LOGE("Initialize finished\n");
		HPostv4_Initialized = TRUE;
	}

	for(f=0; f<num_fft; f++){
		fft();
	}
	
	
	
	
	
	
	//YHistA.TBL_addset_tr(YP.reshape(1), UPDATE_TABLE, UPDATE_TABLE_SBIT, tr_pow);
	for(f=0; f<num_fft; f++){
		//// TAKIGAHIRA : for 64bit build support
		////ptemp = (long *)&X1[f];
		ptemp = (int *)&X1[f];
		ltemp = *ptemp;
		//LOGI("f=%d : ltemp = %d\n", f, ltemp); // KAMA

		ltemp >>= LOCAL_DEFAULT_UPDATE_TABLE_SBIT;
		//// TAKIGAHIRA : for 64bit build support
		////n1 = (long)UPDATE_TABLE[ltemp];
		n1 = (int)UPDATE_TABLE[ltemp];
		//n12 = N2 + n1;
		//N12 = N2 + PF_N;
		//for(rn12=&YHistA[n12]; n12<N12; n12++, rn12+=2){
		for(n12=n1; n12<max_bin; n12++){ // change, PF_N => hrle_info.num_bin
			YHistA[f][n12] += tr_pow; // Elements order was swapped. old) YHistA[n12][f] += tr_pow;
		}
	}

	//for(f=0; f<5; f++){ // TAKIGAHIRA modified loop
	//    LOGI("YHistA[%d][0] = %e\n", f, YHistA[i][0]); // KAMA
	//}

	tr_pow *= tr_inv;

	if(tr_pow>1.0e+20){
		tr_pow *= 1.0e-40; // YHistA *= 1.0e-40;
		LOGI("WARN : tr_pow > 1.0e+20 \n");
	}

	//YHistA.nearest_inc((YHistA.mid1(YHistA.end1()) * Lx), LxI); 	// nearest index, end1=1999
	//High speed spec.
	//void Compmat::nearest_inc(const Compmat& x, Compmat& retval) const
	for(n2=0; n2<num_fft; n2++){
		//xr = YHistA[n2][PF_N-1] * PF_Lx; // Elements order was swapped. old) xr = YHistA[PF_N-1][n2] * PF_Lx;
		xr = YHistA[n2][max_bin-1] * hrle_param.lx;
		n1 = LxI[n2];
		//LOGI("n2=%d : xr=%e, n1=%d\n", n2, xr, n1);

		if(xr < YHistA[n2][n1]){ // backward search // Elements order was swapped. old) if(xr < YHistA[n1][n2]){ ... }
			for(n1--; n1>=0; n1--){
				//LOGI("n2=%d : Y=%f\n", n2, YHistA[n1][n2]*pow(10,20));
				if(xr >= YHistA[n2][n1]){ break; } // Elements order was swapped. old) if(xr >= YHistA[n1][n2]){ break; }
			}
			LxI[n2] = n1 + 1;
			if(n1<0){ continue; }

			ftmp = YHistA[n2][n1] + YHistA[n2][n1+1]; // Elements order was swapped. old) ftmp = YHistA[n1][n2] + YHistA[n1+1][n2];
			//LOGI("n2=%d : ftmp=%f\n", n2, ftmp*pow(10,20));
			ftmp -= xr;
			ftmp -= xr;
			if(ftmp>0){ LxI[n2] -= 1; }
		}
		else{  // forward search
			//for(n1++; n1<PF_N; n1++){
			for(n1++; n1<max_bin; n1++){
				if(xr < YHistA[n2][n1]){ break; } // Elements order was swapped. old) if(xr < YHistA[n1][n2]){ break; }
			}
			LxI[n2] = n1 - 1;
			if(n1==max_bin){ continue; } // change, PF_N => hrle_info.num_bin

			ftmp = YHistA[n2][n1] + YHistA[n2][n1-1]; // Elements order was swapped. old) ftmp = YHistA[n1][n2] + YHistA[n1-1][n2];
			ftmp -= xr;
			ftmp -= xr;
			if(ftmp<0){ LxI[n2] += 1; }
		}
		//LOGI("n2=%d : LxI=%d\n", n2, LxI[n2]);
		Y[n2] = PowV[LxI[n2]];
	}
	//LxP = PowV(LxI.reshape());	<- Yにかえす
	return(OK);
}

///////////////////////////////////////////////////////////////
//  MAIN
int LogisticRegression(
	int	num_src,
	HA_Float	inputSpec[ARY_NUM_SRC][ARY_NUM_FFT],
	HA_Float	outputSpec[ARY_NUM_SRC][ARY_NUM_FFT]
	)
{
	int	s, f;
	const int num_fft = hrle_param.fft_length;

	if(num_src>0){
		/* 2013.03.05 K.Takagi X=X1のためバッファコピー省略
		//for(s=0; s<num_src; s++){
		//	for(f=0; f<num_fft; f++){
		//		X[s][f] = inputSpec[s][f];
		//		//if(f<10){ LOGI("f=%d : X=%f\n", f, X[s][f]); }
		//	}
		//}
		*/
		// postfilterの実行（各音源について、内部推定雑音ヒストグラムは共通に利用）
		// ＋出力用変数mNoiseSpecvalue( map<int, vector<float> >型) の各要素にデータを詰める

		for(s=0; s<num_src; s++){ // 音源のループ
			//X1 = X.mid1(nsrc);	// <- 単にsrcの位置のデータを抜き出すだけ。作業用。
			for(f=0; f<num_fft; f++){
				X1[f] = inputSpec[s][f]; //X1[f] = X[s][f];
			}

			//Y = PF.execute(X1); // Yには各音源でのノイズ推定値が入る
			PF_execute(X1, Y);

			for(f=0; f<num_fft; f++){
				outputSpec[s][f] = Y[f];	// vector<float>につめる
				//if(s==2){ LOGI("f=%d : outputSpec=%f\n", f, outputSpec[s][f]); }
				//if(f<10){ LOGI("f=%d : outputSpec=%f\n", f, outputSpec[s][f]); }
			}
		}
		//exit(0);
	}
	return(OK);
}
#endif // BUILD_MODULE_HRLE

// EOF





/*
gamfit(R){
    m1 = mean(R);
    m2 = mean(log(R));
    s = log(m1) - m2;
    k = (3 - s + sqrt((s-3).^2 + 24.*s)) ./ (12.*s);
    k = fzero(@(x) log(x)-psi(x)-s, k);
    res (1) = k;
    res (2) = m1 / k;
}
*/

/*
gamfit(int num, float *x){ // num is x size
    float m1, m2, s, k, phat[2];
    m1 = 0.0f;
    for(i=0; i<num; i++){
        m1 += x[i];
    }
    m1 /= num;

    m2 = 0.0f;
    for(i=0; i<num; i++){
        m2 += log(x[i]);
    }
    m2 /= num;

    s = log(m1) - m2;
    k = (3 - s + sqrt((s-3)*(s-3) + 24*s)) / (12*s);
    //k = (3 - s + sqrt((s+18)*s+9)) / (12*s); //若干高速だが僅かに誤差が出る
    k = fzero(log(x)-psi(x)-s, k);
    phat[0] = k;
    phat[1] = m1 / k;
    return phat;
}
*/


// matlab used "Forsythe, G. E., M. A. Malcolm, and C. B. Moler, Computer Methods for Mathematical Computations, Prentice-Hall, 1976." algorithm.
// but, more new algorithm was used by octave. this function based on octave's algorithm. please refer to following.

// This is essentially the ACM algorithm 748: Enclosing Zeros of Continuous Functions due to G.E.Alefeld, F.A.Potra and Yixun Shi,
// ACM Transactions on Mathematical Software, Vol. 21, No. 3, September 1995, P.327-344.
// Although the workflow should be the same, the structure of the algorithm has been transformed non-trivially;
// instead of the authors' approach of sequentially calling building blocks subprograms we implement here a FSM version using one
// interior point determination and one bracketing per iteration, thus reducing the number of temporary variables and simplifying
// the algorithm structure. Further, this approach reduces the need for external functions and error handling.
// The algorithm has also been slightly modified.

// Please refer to following. ACM digital library "Algorithm 748: enclosing zeros of continuous functions"
// http://dl.acm.org/citation.cfm?id=210111&picked=formats&CFID=397095046&CFTOKEN=91592471
//
// appendices and supplements sample program of algorithm 748 (Fortran code)
// http://dl.acm.org/ft_gateway.cfm?id=210111&type=gz&path=%2F220000%2F210111%2Fsupp%2F748%2Egz&supp=1&dwn=1&CFID=397095046&CFTOKEN=91592471

// 逆三次補間を可能な限り採用し、不可能な場合は二次補間＋ニュートン法を用いる。また、次の点で単調性を失う場合も逆三次補間を無効化する。
// セカント法と二分法を併用し、セカント法で極端に大きな移動が発生した場合は二分法に切換える

/*
//function [x, fval, info, output] = fzero (fun, x0, options = struct ()){
//float fzero(void* fun, int nx0, float x0[]){ //nx0:開始点or区間[1:開始点, 2:区間, その他:エラー]
float fzero(void* fun, float x0){ //区間指定を削除
    float a, b, c, d, e, fa, fb, fc, fd, fe;
    float x; //, fval;
    float mba, aa, b_tmp[10];
    float q11, q21, q31, d21, d31, q22, q32, d32, q33; // for Inverse cubic interpolation.
    float a0, a1, a2, pc, pdc;
    float tolx; //tolx:現在点xに対する終了許容誤差"TolX"
    int info; //info:exit時の状態[1:関数が解xに収束した, -5:特異点に収束した可能性がある, matlab互換の値で他は発生しない]
    //int niter, nfev, maxiter, maxfev; //niter:反復回数 , nfev:関数評価回数 , maxiter:反復の最大許容回数"MaxIter", maxfev:可能な関数評価の最大回数"MaxFunEvals"
    int can_cubic; // 逆三次補完が可能な条件か判定するフラグ
    const static float mu  = 0.5f;
    const static float eps = 2e-23;
    //maxiter = <<arg or Inf>>; maxfev = <<arg or Inf>>; // とりあえず無制限
    tolx = 1e-8;

    // The default exit flag if exceeded number of iterations.
    info = 0; //niter = 0; nfev = 0;

    x = a = fa = b = fb = 0.0f/0.0f; //NaN;
    //x = fval = a = fa = b = fb = 0.0f/0.0f; //NaN; //fvalはいらないので削除

    // Prepare...
    //switch(nx0){ //区間指定を削除したので条件分岐も削除
    //case 2:
    //    a = x0[0]; fa = fun(a); //nfev++;
    //    b = x0[1]; fb = fun(b); //nfev++;
    //    break;
    //case 1:
    //default:
    //    a = x0[0]; fa = fun(a); //nfev++;
        a = x0; fa = fun(a); //nfev++;
        // Try to get b.
        aa = (a == 0.0f) ? 1.0f : a;
        b_tmp[9] = 0.9f * aa;
        b_tmp[8] = 1.1f * aa;
        b_tmp[7] = aa - 1.0f;
        b_tmp[6] = aa + 1.0f;
        b_tmp[5] = 0.5f * aa;
        b_tmp[4] = 1.5f * aa;
        b_tmp[3] = -aa;
        b_tmp[2] = 2.0f * aa;
        b_tmp[1] = -10.0f * aa;
        b_tmp[0] = 10.0f * aa;
        //for(int i=9; i>=0; i--){
        //    b = b_tmp[i]; fb = fun(b); //nfev++;
        //    //if(sign(fa) * sign(fb) <= 0){ break; }
        //    if(fa == 0.0f || fb == 0.0f || (fa < 0.0f && fb > 0.0f) || (fa > 0.0f && fb < 0.0f)){ break; }
        //}
        if(fa == 0.0f){
            b = b_tmp[9]; fb = fun(b); //nfev++;
        }
        else if(fa < 0.0f){
            for(int i=9; i>=0; i--){
                b = b_tmp[i]; fb = fun(b); //nfev++;
                if(fb >= 0.0f){ break; }
            }
        }
        else{ // fa > 0.0f
            for(int i=9; i>=0; i--){
                b = b_tmp[i]; fb = fun(b); //nfev++;
                if(fb <= 0.0f){ break; }
            }
        }
    //    break;
    //}

    if(b < a){ u=a; a=b; b=u; fu=fa; fa=fb; fb=fu; } //swap(a<=>b)

    if((fa > 0.0f && fb > 0.0f) || (fa < 0.0f && fb < 0.0f)){ //if(!(sign(fa)*sign(fb)<=0))と等価 // 初期区間エラー
        LOGD("fzero:bracket", "fzero: not a valid initial bracketing");
    }

    slope0 = (fb - fa) / (b - a);

    itype = 1;

    if(absf(fa) < absf(fb)){ if(fa == 0.0f){ b = a; fb = fa; } u = a; fu = fa; }
    else{                    if(fb == 0.0f){ a = b; fa = fb; } u = b; fu = fb; }

    d = e = u;
    fd = fe = fu;
    mba = mu * (b - a);
    //while(niter < maxiter && nfev < maxfev){
    while(1){ // とりあえず関数評価回数と反復許容回数は無制限
        switch(itype){
        case 1: // The initial test.
            if(b - a <= 2.0f * (2.0f * absf(u) * eps + tolx)){
                x = u; //fval = fu; //fvalはいらないので削除
                info = 1;
                break;
            }
            if(absf(fa) <= 1e3 * absf(fb) && absf(fb) <= 1e3 * absf(fa)){ // Secant step. //セカント法
                c = u - (a - b) / (fa - fb) * fu;
            }
            else{ // Bisection step. //二分法
                c = 0.5f * (a + b);
            }
            //d = u; fd = fu;
            itype = 5;
            break;
        case 2:
        case 3:
            can_cubic = (fa==fb || fa==fd || fa==fe || fb==fd || fb==fe || fd==fe) ? 0 : 1; //unique([fa, fb, fd, fe])==4と等価
            if(can_cubic){ // Inverse cubic interpolation. // 逆三次補完
                q11 = (d - e) * fd / (fe - fd);
                q21 = (b - d) * fb / (fd - fb);
                q31 = (a - b) * fa / (fb - fa);
                d21 = (b - d) * fd / (fd - fb);
                d31 = (a - b) * fb / (fb - fa);
                q22 = (d21 - q11) * fb / (fe - fb);
                q32 = (d31 - q21) * fa / (fd - fa);
                d32 = (d31 - q21) * fd / (fd - fa);
                q33 = (d32 - q22) * fa / (fe - fa);
                c = a + q31 + q32 + q33;
            }
            if(!can_cubic || (((c - a) > 0.0f && (c - b) > 0.0f) || ((c - a) < 0.0f && (c - b) < 0.0f))){ //if(!can_cubic || sign(c-a)*sign(c-b)>0)と等価 // Quadratic interpolation + newton. //二次補間＋ニュートン法
                a0 = fa;
                a1 = (fb - fa) / (b - a);
                a2 = ((fd - fb) / (d - b) - a1) / (d - a);
                // Modification 1: this is simpler and does not seem to be worse.
                c = a - a0 / a1;
                if(a2 != 0.0f){
                    for(int i=itype; i>0; i--){
                        pdc = a1 + a2 * (2.0f * c - a - b);
                        if(pdc == 0.0f){ c = a - a0 / a1; break; } // terminate for avoid 0 divide.
                        pc = a0 + (a1 + a2 * (c - b)) * (c - a);
                        c -= pc / pdc;
                    }
                }
            }
            itype++;
            break;
        case 4: // Double secant step. //セカント法
            c = u - 2.0f * (b - a) / (fb - fa) * fu;
            if(absf(c - u) > 0.5f * (b - a)){ c = 0.5f * (b + a); } // Bisect if too far. //次の点cが区間の半分以上遠方になる場合は二分法を採用
            itype = 5;
            break;
        case 5: // Bisection step. //二分法
            c = 0.5f * (b + a);
            itype = 2;
            break;
        }

        // Don't let c come too close to a or b.
        delta = 2.0f * 0.7f * (2.0f * absf(u) * eps + tolx);
        if((b - a) <= 2.0f * delta){
            c = (a + b) * 0.5f;
        }
        else{
            //c = max(a + delta, min(b - delta, c));
            c = ((b - delta >= c) ? c : b - delta); // c = min(b - delta, c);と等価
            c = ((a + delta > c) ? a + delta : c);  // c = max(a + delta, c);と等価
        }

        // Calculate new point.
        x = c;
        fc = fun(c);
        //fval = fc = fun(c); //fvalはいらないので削除
        //niter++; nfev++;

        // Modification 2: skip inverse cubic interpolation if nonmonotonicity is detected.
        //次の点であるcにおいて単調性を失った場合に逆三次補間を無効化(fe=fcつまり次のループでfa==fe||fb==feとなるように)する
        if((fc - fa) == 0.0f || (fc - fb) == 0.0f || ((fc - fa) > 0.0f && (fc - fb) > 0.0f) || ((fc - fa) < 0.0f && (fc - fb) < 0.0f)){ //if(sign(fc-fa)*sign(fc-fb)>=0)と等価
            fe = fc;
        }
        else{
            e = d; fe = fd;
        }

        // Bracketing.
        if((fa < 0.0f && fc > 0.0f) || (fa > 0.0f && fc < 0.0f)){ //if(sign(fa)*sign(fc)<0)と等価
            d = b; fd = fb;
            b = c; fb = fc;
        }
        else if((fb < 0.0f && fc > 0.0f) || (fb > 0.0f && fc < 0.0f)){ //else if(sign(fb)*sign(fc)<0)と等価
            d = a; fd = fa;
            a = c; fa = fc;
        }
        else if(fc == 0.0f){
            a = b = c; fa = fb = fc;
            info = 1;
            break;
        }
        else{ // This should never happen.
            LOGD("fzero:bracket", "fzero: zero point is not bracketed");
        }

        if(absf(fa) < absf(fb)){ u = a; fu = fa; }
        else{                    u = b; fu = fb; }
        if(b - a <= 2.0f * (2.0f * absf(u) * eps + tolx)){
            info = 1;
            break;
        }

        // Skip bisection step if successful reduction. // 囲い込み範囲が半分以下(mu==0.5f時)に削減出来たなら二分法ステップをスキップする
        if(itype == 5 && (b - a) <= mba){ itype = 2; }
        if(itype == 2){ mba = mu * (b - a); } // 囲い込み範囲の削減ターゲットmbaを更新する
    }

    // Check solution for a singularity by examining slope
    if(info == 1){
        if((b - a) != 0.0f && absf((fb - fa) / (b - a) / slope0) > max (1e6, 0.5f / (eps + tolx))){
            info = -5;
        }
    }

    //memo :: iterations:niter, funcCount:nfev, bracketx:[a, b], brackety:[fa, fb];
    //memo :: result:x, fun(x):fval

    return x;
}
*/


static inline float gamfit(int num, float *x_array){ // num is x_array size
    float m1, m2, s, k, phat[2];
    float y, twopx, logterm; // temporary variables for fast log function and fast digamma function
    m1 = 0.0f;
    for(i=0; i<num; i++){
        m1 += x_array[i];
    }
    m1 /= num;

    m2 = 0.0f;
    for(i=0; i<num; i++){
        //m2 += log(x_array[i]);
        y = x_array[i];
        union { float f; unsigned int i; } vx = { y };
        union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
        y = vx.i;
        y *= 1.1920928955078125e-7f;
        m2 += 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
    }
    m2 /= num;

    //s = log(m1) - m2;
    {
        union { float f; unsigned int i; } vx = { m1 };
        union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
        y = vx.i;
        y *= 1.1920928955078125e-7f;
        s = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f)) - m2;
    }

    k = (3 - s + sqrt((s-3)*(s-3) + 24*s)) / (12*s);
    //k = (3 - s + sqrt((s+18)*s+9)) / (12*s); //若干高速だが僅かに誤差が出る
    //k = fzero(log(x)-psi(x)-s, k);
    //k = fzero(log(x)-digamma(x)-s, k);
    {
        float a, b, c, d, e, fa, fb, fc, fd, fe;
        float x;
        float mba, aa, b_tmp[10];
        float q11, q21, q31, d21, d31, q22, q32, d32, q33; // for Inverse cubic interpolation.
        float a0, a1, a2, pc, pdc; // for Quadratic interpolation + newton.
        int can_cubic; // 逆三次補完が可能な条件か判定するフラグ
        const static float mu   = 0.5f;
        const static float eps  = 2e-23;
        const static float tolx = 1e-8; //tolx:現在点xに対する終了許容誤差"TolX"

        x = a = fa = b = fb = 0.0f/0.0f; //NaN;

        a = k;
        //fa = log(a)-digamma(a)-s;
        {
            twopx = 2.0f + a;
            union { float f; unsigned int i; } vx = { a };
            union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
            y = vx.i;
            y *= 1.1920928955078125e-7f;
            union { float f; unsigned int i; } vxp2 = { twopx };
            union { unsigned int i; float f; } mxp2 = { (vxp2.i & 0x007FFFFF) | 0x3f000000 };
            logterm = vxp2.i;
            logterm *= 1.1920928955078125e-7f;
            fa = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f))
               - (-48.0f + a * (-157.0f + a * (-127.0f - 30.0f * a))) / (12.0f * a * (1.0f + a) * twopx * twopx)
               - (0.69314718f * (logterm - 124.22551499f - 1.498030302f * mxp2.f - 1.72587999f / (0.3520887068f + mxp2.f)))
               - s;
        }
        // Try to get b.
        aa = (a == 0.0f) ? 1.0f : a;
        b_tmp[9] = 0.9f * aa;   b_tmp[8] = 1.1f * aa;
        b_tmp[7] = aa - 1.0f;   b_tmp[6] = aa + 1.0f;
        b_tmp[5] = 0.5f * aa;   b_tmp[4] = 1.5f * aa;
        b_tmp[3] = -aa;         b_tmp[2] = 2.0f * aa;
        b_tmp[1] = -10.0f * aa; b_tmp[0] = 10.0f * aa;
        if(fa == 0.0f){
            b = b_tmp[9];
            //fb = log(b)-digamma(b)-s;
            {
                twopx = 2.0f + b;
                union { float f; unsigned int i; } vx = { b };
                union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
                y = vx.i;
                y *= 1.1920928955078125e-7f;
                union { float f; unsigned int i; } vxp2 = { twopx };
                union { unsigned int i; float f; } mxp2 = { (vxp2.i & 0x007FFFFF) | 0x3f000000 };
                logterm = vxp2.i;
                logterm *= 1.1920928955078125e-7f;
                fb = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f))
                   - (-48.0f + b * (-157.0f + b * (-127.0f - 30.0f * b))) / (12.0f * b * (1.0f + b) * twopx * twopx)
                   - (0.69314718f * (logterm - 124.22551499f - 1.498030302f * mxp2.f - 1.72587999f / (0.3520887068f + mxp2.f)))
                   - s;
            }
        }
        else if(fa < 0.0f){
            for(int i=9; i>=0; i--){
                b = b_tmp[i];
                //fb = log(b)-digamma(b)-s;
                {
                    twopx = 2.0f + b;
                    union { float f; unsigned int i; } vx = { b };
                    union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
                    y = vx.i;
                    y *= 1.1920928955078125e-7f;
                    union { float f; unsigned int i; } vxp2 = { twopx };
                    union { unsigned int i; float f; } mxp2 = { (vxp2.i & 0x007FFFFF) | 0x3f000000 };
                    logterm = vxp2.i;
                    logterm *= 1.1920928955078125e-7f;
                    fb = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f))
                       - (-48.0f + b * (-157.0f + b * (-127.0f - 30.0f * b))) / (12.0f * b * (1.0f + b) * twopx * twopx)
                       - (0.69314718f * (logterm - 124.22551499f - 1.498030302f * mxp2.f - 1.72587999f / (0.3520887068f + mxp2.f)))
                       - s;
                }
                if(fb >= 0.0f){ break; }
            }
        }
        else{ // fa > 0.0f
            for(int i=9; i>=0; i--){
                b = b_tmp[i];
                //fb = log(b)-digamma(b)-s;
                {
                    twopx = 2.0f + b;
                    union { float f; unsigned int i; } vx = { b };
                    union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
                    y = vx.i;
                    y *= 1.1920928955078125e-7f;
                    union { float f; unsigned int i; } vxp2 = { twopx };
                    union { unsigned int i; float f; } mxp2 = { (vxp2.i & 0x007FFFFF) | 0x3f000000 };
                    logterm = vxp2.i;
                    logterm *= 1.1920928955078125e-7f;
                    fb = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f))
                       - (-48.0f + b * (-157.0f + b * (-127.0f - 30.0f * b))) / (12.0f * b * (1.0f + b) * twopx * twopx)
                       - (0.69314718f * (logterm - 124.22551499f - 1.498030302f * mxp2.f - 1.72587999f / (0.3520887068f + mxp2.f)))
                       - s;
                }
                if(fb <= 0.0f){ break; }
            }
        }

        if(b < a){ u=a; a=b; b=u; fu=fa; fa=fb; fb=fu; } //swap(a<=>b)

        if((fa > 0.0f && fb > 0.0f) || (fa < 0.0f && fb < 0.0f)){ //if(!(sign(fa)*sign(fb)<=0))と等価 // 初期区間エラー
            LOGD("fzero:bracket", "fzero: not a valid initial bracketing");
        }

        itype = 1;

        if(absf(fa) < absf(fb)){ if(fa == 0.0f){ b = a; fb = fa; } u = a; fu = fa; }
        else{                    if(fb == 0.0f){ a = b; fa = fb; } u = b; fu = fb; }

        d = e = u;
        fd = fe = fu;
        mba = mu * (b - a);
        while(1){
            switch(itype){
            case 2:
            case 3:
                can_cubic = (fa==fb || fa==fd || fa==fe || fb==fd || fb==fe || fd==fe) ? 0 : 1; //unique([fa, fb, fd, fe])==4と等価
                if(can_cubic){ // Inverse cubic interpolation. // 逆三次補完
                    q11 = (d - e) * fd / (fe - fd);
                    q21 = (b - d) * fb / (fd - fb);
                    q31 = (a - b) * fa / (fb - fa);
                    d21 = (b - d) * fd / (fd - fb);
                    d31 = (a - b) * fb / (fb - fa);
                    q22 = (d21 - q11) * fb / (fe - fb);
                    q32 = (d31 - q21) * fa / (fd - fa);
                    d32 = (d31 - q21) * fd / (fd - fa);
                    q33 = (d32 - q22) * fa / (fe - fa);
                    c = a + q31 + q32 + q33;
                }
                if(!can_cubic || (((c - a) > 0.0f && (c - b) > 0.0f) || ((c - a) < 0.0f && (c - b) < 0.0f))){ //if(!can_cubic || sign(c-a)*sign(c-b)>0)と等価 // Quadratic interpolation + newton. //二次補間＋ニュートン法
                    a0 = fa;
                    a1 = (fb - fa) / (b - a);
                    a2 = ((fd - fb) / (d - b) - a1) / (d - a);
                    // Modification 1: this is simpler and does not seem to be worse.
                    c = a - a0 / a1;
                    if(a2 != 0.0f){
                        for(int i=itype; i>0; i--){
                            pdc = a1 + a2 * (2.0f * c - a - b);
                            if(pdc == 0.0f){ c = a - a0 / a1; break; } // terminate for avoid 0 divide.
                            pc = a0 + (a1 + a2 * (c - b)) * (c - a);
                            c -= pc / pdc;
                        }
                    }
                }
                itype++;
                break;
            case 4: // Double secant step. //セカント法
                c = u - 2.0f * (b - a) / (fb - fa) * fu;
                if(absf(c - u) > 0.5f * (b - a)){ c = 0.5f * (b + a); } // Bisect if too far. //次の点cが区間の半分以上遠方になる場合は二分法を採用
                itype = 5;
                break;
            case 5: // Bisection step. //二分法
                c = 0.5f * (b + a);
                itype = 2;
                break;
            case 1: // The initial test. //初回だけなので評価順序を最後にする
                if(b - a <= 2.0f * (2.0f * absf(u) * eps + tolx)){
                    x = u; break;
                }
                if(absf(fa) <= 1e3 * absf(fb) && absf(fb) <= 1e3 * absf(fa)){ // Secant step. //セカント法
                    c = u - (a - b) / (fa - fb) * fu;
                }
                else{ // Bisection step. //二分法
                    c = 0.5f * (a + b);
                }
                itype = 5;
                break;
            }

            // Don't let c come too close to a or b.
            // aやbに近づき過ぎないように次の点cを決定する
            delta = 2.0f * 0.7f * (2.0f * absf(u) * eps + tolx);
            if((b - a) <= 2.0f * delta){ c = (a + b) * 0.5f; }
            else{ c = ((b - delta >= c) ? c : b - delta); c = ((a + delta > c) ? a + delta : c); }

            // Calculate new point.
            x = c;
            //fc = log(c)-digamma(c)-s;
            {
                twopx = 2.0f + c;
                union { float f; unsigned int i; } vx = { c };
                union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
                y = vx.i;
                y *= 1.1920928955078125e-7f;
                union { float f; unsigned int i; } vxp2 = { twopx };
                union { unsigned int i; float f; } mxp2 = { (vxp2.i & 0x007FFFFF) | 0x3f000000 };
                logterm = vxp2.i;
                logterm *= 1.1920928955078125e-7f;
                fc = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f))
                   - (-48.0f + c * (-157.0f + c * (-127.0f - 30.0f * c))) / (12.0f * c * (1.0f + c) * twopx * twopx)
                   - (0.69314718f * (logterm - 124.22551499f - 1.498030302f * mxp2.f - 1.72587999f / (0.3520887068f + mxp2.f)))
                   - s;
            }

            // Modification 2: skip inverse cubic interpolation if nonmonotonicity is detected.
            //次の点であるcにおいて単調性を失った場合に逆三次補間を無効化(fe=fcつまり次のループでfa==fe||fb==feとなるように)する
            if((fc - fa) == 0.0f || (fc - fb) == 0.0f || ((fc - fa) > 0.0f && (fc - fb) > 0.0f) || ((fc - fa) < 0.0f && (fc - fb) < 0.0f)){ //if(sign(fc-fa)*sign(fc-fb)>=0)と等価
                fe = fc;
            }
            else{
                e = d; fe = fd;
            }

            // Bracketing.
            if((fa < 0.0f && fc > 0.0f) || (fa > 0.0f && fc < 0.0f)){      d = b; fd = fb; b = c; fb = fc; } // Set next range [a, c].
            else if((fb < 0.0f && fc > 0.0f) || (fb > 0.0f && fc < 0.0f)){ d = a; fd = fa; a = c; fa = fc; } // Set next range [c, b].
            else if(fc == 0.0f){ a = b = c; fa = fb = fc; break; } // Solved.
            else{ LOGD("fzero:bracket", "fzero: zero point is not bracketed"); } // This should never happen.

            if(absf(fa) < absf(fb)){ u = a; fu = fa; }
            else{                    u = b; fu = fb; }
            if(b - a <= 2.0f * (2.0f * absf(u) * eps + tolx)){ break; } // Solved.

            // Skip bisection step if successful reduction. // 囲い込み範囲が半分以下(mu==0.5f時)に削減出来たなら二分法ステップをスキップする
            if(itype == 5 && (b - a) <= mba){ itype = 2; }
            if(itype == 2){ mba = mu * (b - a); } // 囲い込み範囲の削減ターゲットmbaを更新する
        }

        k = x;
    }
    phat[0] = k;
    phat[1] = m1 / k;
    return phat;
}


















































/*
// a, b scalar case only
static inline float gampdf(int num, float *x, float a, float b){ // num is x size
    float pdf[num];
    for(i=0; i<num; i++){
        pdf[i] = 0.0f;
        //if(Nan or a<=0 or b<=0){ pdf[i]=Nan; }
    }

    if(a>0 && a<=1 && b>0){ // 0<a<=1, 0<b
        for(i=0; i<num; i++){
            if(x[i]>=0){
                pdf[i] = (x[i] ^ (a - 1)) * exp(- x[i] / b) / gamma(a) / (b ^ a);
            }
        }
    }
    else if(a>1 && b>0){ // 1<a, 0<b
        for(i=0; i<num; i++){
            if(x[i]>=0){
                pdf[i] = exp (- a * log(b) + (a-1) * log(x[i]) - x[i] / b - gammaln(a));
            }
        }
    }

    return pdf;
}
*/

// a, b scalar case only
static inline float gampdf(int num, float *x, float a, float b){ // num is x size
    float pdf[num];
    float y, logterm, logxp3;
    float offset, clipy, z;
    int w;
    float exp_neg_x_div_b, gamma_a, log_b, log_x, gammaln_a;
    float pow_x_am1, pow_b_a;
    for(i=0; i<num; i++){
        pdf[i] = 0.0f;
        //if(Nan or a<=0 or b<=0){ pdf[i]=Nan; }
    }

    if(a>0 && a<=1 && b>0){ // 0<a<=1, 0<b
        {
            y = a * (1.0f + a) * (2.0f + a);
            union { float f; unsigned int i; } vx = { y };
            union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
            y = vx.i;
            y *= 1.1920928955078125e-7f;
            logterm = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
            y = 3.0f + a;
            vx = { y };
            mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
            y = vx.i;
            y *= 1.1920928955078125e-7f;
            logxp3 = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
            y = - 2.081061466f - a + 0.0833333f / (3.0f + a) - logterm + (2.5f + a) * logxp3; // y = gammaln(a);
            offset = (y < 0.0f) ? 1.0f : 0.0f;
            clipy = (y < -126.0f) ? -126.0f : y;
            w = clipy;
            z = clipy - w + offset;
            union { unsigned int i; float f; } v = { (unsigned int) ( (1 << 23) * (clipy + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };
            gamma_a = v.f * 1.442695040f; // gamma_a = exp(gammaln(a));
        }
        {
            union { double d; int i[2]; } b_val = { (double) b };
            union { double d; int i[2]; } pow_val;
            pow_val.i[1] = (int) ((b_val.i[1] - 1072632447) * a + 1072632447);
            pow_val.i[0] = 0;
            pow_b_a = (float) pow_val.d;
        }
        for(i=0; i<num; i++){
            if(x[i]>=0){
                //pdf[i] = (x[i] ^ (a - 1)) * exp(- x[i] / b) / gamma(a) / (b ^ a);
                {
                    y = x[i];
                    union { double d; int i[2]; } y_val = { (double) y };
                    union { double d; int i[2]; } pow_val;
                    pow_val.i[1] = (int) ((y_val.i[1] - 1072632447) * (a-1.0f) + 1072632447);
                    pow_val.i[0] = 0;
                    pow_x_am1 = (float) pow_val.d;
                }
                {
                    y = -x[i] / b;
                    offset = (y < 0.0f) ? 1.0f : 0.0f;
                    clipy = (y < -126.0f) ? -126.0f : y;
                    w = clipy;
                    z = clipy - w + offset;
                    union { unsigned int i; float f; } v = { (unsigned int) ( (1 << 23) * (clipy + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };
                    exp_neg_x_div_b = v.f * 1.442695040f;
                }
                pdf[i] = pow_x_am1 * exp_neg_x_div_b / gamma_a / pow_b_a;
            }
        }
    }
    else if(a>1 && b>0){ // 1<a, 0<b
        {
            union { float f; unsigned int i; } vx = { b };
            union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
            y = vx.i;
            y *= 1.1920928955078125e-7f;
            log_b = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
        }
        {
            y = a * (1.0f + a) * (2.0f + a);
            union { float f; unsigned int i; } vx = { y };
            union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
            y = vx.i;
            y *= 1.1920928955078125e-7f;
            logterm = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
            y = 3.0f + a;
            vx = { y };
            mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
            y = vx.i;
            y *= 1.1920928955078125e-7f;
            logxp3 = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
            gammaln_a = - 2.081061466f - a + 0.0833333f / (3.0f + a) - logterm + (2.5f + a) * logxp3;
        }
        for(i=0; i<num; i++){
            if(x[i]>=0){
                //pdf[i] = exp (- a * log(b) + (a-1) * log(x[i]) - x[i] / b - gammaln(a));
                {
                    y = x[i];
                    union { float f; unsigned int i; } vx = { y };
                    union { unsigned int i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
                    y = vx.i;
                    y *= 1.1920928955078125e-7f;
                    log_x = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
                }
                {
                    y = - a * log_b + (a-1) * log_x - x[i] / b - gammaln_a;
                    offset = (y < 0.0f) ? 1.0f : 0.0f;
                    clipy = (y < -126.0f) ? -126.0f : y;
                    w = clipy;
                    z = clipy - w + offset;
                    union { unsigned int i; float f; } v = { (unsigned int) ( (1 << 23) * (clipy + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };
                    pdf[i] = v.f * 1.442695040f;
                }
            }
        }
    }

    return pdf;
}




static inline float myexp(float p)
{
  float offset = (p < 0) ? 1.0f : 0.0f;
  float clipp = (p < -126) ? -126.0f : p;
  int w = clipp;
  float z = clipp - w + offset;
  union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };

  return v.f * 1.442695040f;
}

static inline float mylog(float x)
{
    union { float f; uint32_t i; } vx = { x };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    float y = vx.i;
    y *= 1.1920928955078125e-7f;

    return 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
}

static inline float mylgamma(float x)
{
    float y, logterm, logxp3;

    y = x * (1.0f + x) * (2.0f + x);
    union { float f; uint32_t i; } vx = { y };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    y = vx.i;
    y *= 1.1920928955078125e-7f;
    logterm = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));

    y = 3.0f + x;
    union { float f; uint32_t i; } vx = { y };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    y = vx.i;
    y *= 1.1920928955078125e-7f;
    logxp3 = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));

    return - 2.081061466f - x + 0.0833333f / (3.0f + x) - logterm + (2.5f + x) * logxp3;
}

static inline float mygamma(float x)
{
    float y, logterm, logxp3, p;

    y = x * (1.0f + x) * (2.0f + x);
    union { float f; uint32_t i; } vx = { y };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    y = vx.i;
    y *= 1.1920928955078125e-7f;
    logterm = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));

    y = 3.0f + x;
    union { float f; uint32_t i; } vx = { y };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    y = vx.i;
    y *= 1.1920928955078125e-7f;
    logxp3 = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));

    p = - 2.081061466f - x + 0.0833333f / (3.0f + x) - logterm + (2.5f + x) * logxp3; // p = gammaln(x);

    float offset, clipp, z;
    int w;
    offset = (p < 0.0f) ? 1.0f : 0.0f;
    clipp = (p < -126.0f) ? -126.0f : p;
    w = clipp;
    z = clipp - w + offset;
    union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };

    return v.f * 1.442695040f; // ret = exp(p);
}






/**
* Gamma function.
* Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz<BR>
* Applied Mathematics Division<BR>
* Argonne National Laboratory<BR>
* Argonne, IL 60439<BR>
* <P>
* References:
* <OL>
* <LI>"An Overview of Software Development for Special Functions", W. J. Cody, Lecture Notes in Mathematics, 506, Numerical Analysis Dundee, 1975, G. A. Watson (ed.), Springer Verlag, Berlin, 1976.
* <LI>Computer Approximations, Hart, Et. Al., Wiley and sons, New York, 1968.
* </OL></P><P>
* From the original documentation:
* </P><P>
* This routine calculates the GAMMA function for a real argument X.
* Computation is based on an algorithm outlined in reference 1.
* The program uses rational functions that approximate the GAMMA
* function to at least 20 significant decimal digits.  Coefficients
* for the approximation over the interval (1,2) are unpublished.
* Those for the approximation for X .GE. 12 are from reference 2.
* The accuracy achieved depends on the arithmetic system, the
* compiler, the intrinsic functions, and proper selection of the
* machine-dependent constants.
* </P><P>
* Error returns:<BR>
* The program returns the value XINF for singularities or when overflow would occur.
* The computation is believed to be free of underflow and overflow.
* </P>
* @return Double.MAX_VALUE if overflow would occur, i.e. if abs(x) > 171.624
* @jsci.planetmath GammaFunction
* @author Jaco van Kooten
*/

/*
// Some IEEE machine constants

// Relative machine precision.
//static double EPS=2.22e-16;
static float EPS=1.192e-7;
// The smallest positive floating-point number such that 1/xminin is machine representable.
//static double XMININ=2.23e-308;
static float XMININ=5.89e-39;


// Gamma function related constants
static float g_p[8] = {  66456.1438202405440627855f, -36144.4134186911729807069f, -31451.2729688483675254357f,  866.966202790413211295064f,
                         629.331155312818442661052f, -379.804256470945635097577f,  24.7656508055759199108314f, -1.71618513886549492533811f };
static float g_q[8] = { -115132.259675553483497211f, -134659.959864969306392456f,  4755.84627752788110767815f,  22538.1184209801510330112f,
                        -3107.77167157231109440444f, -1015.15636749021914166146f,  315.350626979604161529144f, -30.8402300119738975254353f };
static float g_c[7] = {  0.08333333333333333331554247f, -0.002777777777777681622553f,
                         7.93650793500350248e-4, -5.952379913043012e-4,  8.4171387781295e-4,  -0.001910444077728f,  0.0057083835261f };
// The largest argument for which <code>gamma(x)</code> is representable in the machine.
//static double GAMMA_X_MAX_VALUE = 171.624;
static float GAMMA_X_MAX_VALUE = 33.843f;
static float SQRT2PI = 2.5066282746310007f;
static float LOGSQRT2PI = log(SQRT2PI);


float gamma(float x){
    float fact=1.0f, xden, xnum;
    int i, n=0;
    float y=x, z, y1;
    int parity=0;
    float res, sum, ysq;

    if(y == 0.0f){ return FLAOT_MAX_VALUE; } // Argument is zero
    else if(y < 0.0f){ // Argument is negative
        y = -(x);
        y1 = (int)y;
        res = y - y1;
        if(y1 != (((int)(y1*0.5f)) * 2.0f)){ parity = 1; }
        fact = -M_PI/ sin(M_PI * res);
        y += 1.0f;
    }
    // Argument is positive
    if(y < EPS){ // Argument < EPS
        if(y >= XMININ){ res = 1.0f / y; }
        else{ return FLOAT_MAX_VALUE; }
    }
    else if(y < 12.0f){
        y1 = y;
        if(y < 1.0f){ // 0.0 < (EPS) <= argument < 1.0
            z = y;
            y += 1.0f;
        }
        else{ // 1.0 <= argument < 12.0, reduce argument if necessary
            n = (int)y - 1;
            y -= (float) n;
            z = y - 1.0f;
        }
        // Evaluate approximation for 1.0 <= argument < 2.0
        xnum = 0.0f;
        xden = 1.0f;
        for(i=7; i>=0; i--){
            xnum = (xnum + g_p[i]) * z;
            xden = xden * z + g_q[i];
        }
        res = xnum / xden + 1.0;
        if(y1 < y){ // Adjust result for case  0.0 < argument < 1.0
            res /= y1;
        }
        else if(y1 > y){ // Adjust result for case  2.0 < argument < 12.0
            for(i=n; i>0; i--){ res *= y; y += 1.0f; } // for(i=0; i<n; ++i)
        }
    }
    else{ // Evaluate for argument <= 12.0
        if(y <= GAMMA_X_MAX_VALUE){
            ysq = y * y;
            sum = g_c[6];
            for(i=0; i<6; ++i){
                sum = sum / ysq + g_c[i];
            }
            sum = sum / y - y + LOGSQRT2PI;
            sum += (y - 0.5f) * log(y);
            res = exp(sum);
        }
        else{
            return FLOAT_MAX_VALUE;
        }
    }
    // Final adjustments and return
    if(parity){
        res = -res;
    }
    if(fact != 1.0f){
        res = fact / res;
    }
    return res;
} 

*/







/*
static inline float fastlgamma (float x)
{
  float logterm = mylog (x * (1.0f + x) * (2.0f + x));
  float xp3 = 3.0f + x;

  return - 2.081061466f 
         - x 
         + 0.0833333f / xp3 
         - logterm 
         + (2.5f + x) * mylog (xp3);
}

static inline float fastlog(float x)
{
  return 0.69314718f * mylog2 (x);
}

static inline float fastlog2(float x)
{
    union { float f; uint32_t i; } vx = { x };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    float y = vx.i;
    y *= 1.1920928955078125e-7f;

    return y - 124.22551499f
             - 1.498030302f * mx.f 
             - 1.72587999f / (0.3520887068f + mx.f);
}

static inline float fastpow2(float p)
{
  float offset = (p < 0) ? 1.0f : 0.0f;
  float clipp = (p < -126) ? -126.0f : p;
  int w = clipp;
  float z = clipp - w + offset;
  union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };

  return v.f;
}

static inline float fastexp(float p)
{
  return fastpow2 (1.442695040f * p);
}




*/

static inline float myexp(float p)
{
  float ret;
  float offset = (p < 0) ? 1.0f : 0.0f;
  float clipp = (p < -126) ? -126.0f : p;
  int w = clipp;
  float z = clipp - w + offset;
  union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };

  return v.f * 1.442695040f;
}

static inline float mylog(float x)
{
    union { float f; uint32_t i; } vx = { x };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    float y = vx.i;
    y *= 1.1920928955078125e-7f;

    return 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));
}

static inline float mydigamma(float x)
{
  float twopx = 2.0f + x;
  float logterm = mylog (twopx);

  return (-48.0f + x * (-157.0f + x * (-127.0f - 30.0f * x))) /
         (12.0f * x * (1.0f + x) * twopx * twopx)
         + logterm;
}

static inline float mylgamma(float x)
{
    float y, logterm, logxp3;

    y = x * (1.0f + x) * (2.0f + x);
    union { float f; uint32_t i; } vx = { y };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    y = vx.i;
    y *= 1.1920928955078125e-7f;
    logterm = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));

    y = 3.0f + x;
    union { float f; uint32_t i; } vx = { y };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    y = vx.i;
    y *= 1.1920928955078125e-7f;
    logxp3 = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));

    return - 2.081061466f - x + 0.0833333f / (3.0f + x) - logterm + (2.5f + x) * logxp3;
}

static inline float mygamma(float x)
{
    float y, logterm, logxp3, p;

    y = x * (1.0f + x) * (2.0f + x);
    union { float f; uint32_t i; } vx = { y };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    y = vx.i;
    y *= 1.1920928955078125e-7f;
    logterm = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));

    y = 3.0f + x;
    union { float f; uint32_t i; } vx = { y };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    y = vx.i;
    y *= 1.1920928955078125e-7f;
    logxp3 = 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f));

    p = - 2.081061466f - x + 0.0833333f / (3.0f + x) - logterm + (2.5f + x) * logxp3; // p = gammaln(x);

    float offset, clipp, z;
    int w;
    offset = (p < 0) ? 1.0f : 0.0f;
    clipp = (p < -126) ? -126.0f : p;
    w = clipp;
    z = clipp - w + offset;
    union { uint32_t i; float f; } v = { cast_uint32_t ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };

    return v.f * 1.442695040f; // ret = exp(p);
}

static inline float log_sub_digamma(float x)
{
    float twopx = 2.0f + x;
    union { float f; uint32_t i; } vx = { x };
    union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
    float y = vx.i;
    y *= 1.1920928955078125e-7f;

    union { float f; uint32_t i; } vxp2 = { twopx };
    union { uint32_t i; float f; } mxp2 = { (vxp2.i & 0x007FFFFF) | 0x3f000000 };
    float logterm = vxp2.i;
    logterm *= 1.1920928955078125e-7f;

    return 0.69314718f * (y - 124.22551499f - 1.498030302f * mx.f - 1.72587999f / (0.3520887068f + mx.f))
         - (-48.0f + x * (-157.0f + x * (-127.0f - 30.0f * x))) / (12.0f * x * (1.0f + x) * twopx * twopx)
         - (0.69314718f * (logterm - 124.22551499f - 1.498030302f * mxp2.f - 1.72587999f / (0.3520887068f + mxp2.f)));
}

/*
// 
float std(int num, float *x, opt = 0, dim){ // num is x size
    opt = 0;
    nd = ndims (x);
    sz = size (x);
    (dim = find (sz > 1, 1)) || (dim = 1);
    n = sz(dim);
    if(num == 1){
        retval = 0.0f;
    }
    else{
        float tmp=0.0f, tmp2=0.0f;
        for(i=0; i<num; i++){
            tmp+=x[i];
        }
        tmp/=num; //tmp=mean(x)
        for(i=0; i<num; i++){
            tmp2+=(x[i]-tmp)*(x[i]-tmp); //tmp2=sumsq(center(x))
        }
        retval = sqrt(tmp2 / (n - 1 + opt));
    }
    return retval;
}

stdnormal_pdf(float x){
    return (2.0f * pi)^(-0.5f) * exp (- x * x * 0.5f);
}

// a, b scalar case only
static inline float
//normpdf(int num, float *x, float mu = 0, float sigma = 1){ // num is x size
normpdf(int num, float *x){ // num is x size
    float pdf[num];
    for(i=0; i<num; i++){
        pdf[i] = 0.0f;
        //if(Nan or mu!=Nan or mu!=Inf or sigma<=0 or sigma!=Inf){ pdf[i]=Nan; }
    }

    //pdf = stdnormal_pdf ((x - mu) / sigma) / sigma;
    for(i=0; i<num; i++){
        pdf[i] = (2.0f * pi)^(-0.5f) * exp (- x[i] * x[i] * 0.5f);
    }

    return pdf;
}
*/

static inline float normpdf(int num, float *x, float mu, float sigma){ // num is x size
    float p, offset, clipp;
    float pow_pi2;
    float pdf[num];
    for(i=0; i<num; i++){
        pdf[i] = 0.0f;
        //if(Nan or mu!=Nan or mu!=Inf or sigma<=0 or sigma!=Inf){ pdf[i]=Nan; }
    }

    //pdf = stdnormal_pdf ((x - mu) / sigma) / sigma;
    {
        union { double d; int i[2]; } pi2_val = { 2.0 * 3.1415926535897932384626433832795028841968 };
        union { double d; int i[2]; } pow_val;
        pow_val.i[1] = (int) ((pi2_val.i[1] - 1072632447) * (-0.5f) + 1072632447);
        pow_val.i[0] = 0;
        pow_pi2 = (float) pow_val.d; // pow_pi2 = (2.0f * pi)^(-0.5f);
    }
    for(i=0; i<num; i++){
        //pdf[i] = (2.0f * pi)^(-0.5f) * exp (- x[i] * x[i] * 0.5f); //但し x = (arg_x - mu) / sigma;
        p = (x[i] - mu) / sigma;
        p *= p;
        p *= -0.5f;
        offset = (p < 0.0f) ? 1.0f : 0.0f;
        clipp = (p < -126.0f) ? -126.0f : p;
        int w = clipp;
        float z = clipp - w + offset;
        union { unsigned int i; float f; } v = { (unsigned int) ( (1 << 23) * (clipp + 121.2740575f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z) ) };
        pdf[i] = v.f * 1.442695040f * pow_pi2;
    }

    return pdf;
}









//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//==================================================================================================

//======== fzero() ==================================================================================
/*
## Copyright (C) 2008-2012 VZLU Prague, a.s.
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.
##
## Author: Jaroslav Hajek <highegg@gmail.com>

## -*- texinfo -*-
## @deftypefn  {Function File} {} fzero (@var{fun}, @var{x0})
## @deftypefnx {Function File} {} fzero (@var{fun}, @var{x0}, @var{options})
## @deftypefnx {Function File} {[@var{x}, @var{fval}, @var{info}, @var{output}] =} fzero (@dots{})
## Find a zero of a univariate function.
##
## @var{fun} is a function handle, inline function, or string
## containing the name of the function to evaluate.
## @var{x0} should be a two-element vector specifying two points which
## bracket a zero.  In other words, there must be a change in sign of the
## function between @var{x0}(1) and @var{x0}(2).  More mathematically, the
## following must hold
##
## @example
## sign (@var{fun}(@var{x0}(1))) * sign (@var{fun}(@var{x0}(2))) <= 0
## @end example
##
## If @var{x0} is a single scalar then several nearby and distant
## values are probed in an attempt to obtain a valid bracketing.  If this
## is not successful, the function fails.
## @var{options} is a structure specifying additional options.
## Currently, @code{fzero}
## recognizes these options: @code{"FunValCheck"}, @code{"OutputFcn"},
## @code{"TolX"}, @code{"MaxIter"}, @code{"MaxFunEvals"}.
## For a description of these options, see @ref{doc-optimset,,optimset}.
##
## On exit, the function returns @var{x}, the approximate zero point
## and @var{fval}, the function value thereof.
## @var{info} is an exit flag that can have these values:
##
## @itemize
## @item 1
##  The algorithm converged to a solution.
##
## @item 0
##  Maximum number of iterations or function evaluations has been reached.
##
## @item -1
## The algorithm has been terminated from user output function.
##
## @item -5
## The algorithm may have converged to a singular point.
## @end itemize
##
## @var{output} is a structure containing runtime information about the
## @code{fzero} algorithm.  Fields in the structure are:
##
## @itemize
## @item iterations
##  Number of iterations through loop.
##
## @item nfev
##  Number of function evaluations.
##
## @item bracketx
##  A two-element vector with the final bracketing of the zero along the x-axis.
##
## @item brackety
##  A two-element vector with the final bracketing of the zero along the y-axis.
## @end itemize
## @seealso{optimset, fsolve}
## @end deftypefn

## This is essentially the ACM algorithm 748: Enclosing Zeros of
## Continuous Functions due to Alefeld, Potra and Shi, ACM Transactions
## on Mathematical Software, Vol. 21, No. 3, September 1995. Although
## the workflow should be the same, the structure of the algorithm has
## been transformed non-trivially; instead of the authors' approach of
## sequentially calling building blocks subprograms we implement here a
## FSM version using one interior point determination and one bracketing
## per iteration, thus reducing the number of temporary variables and
## simplifying the algorithm structure. Further, this approach reduces
## the need for external functions and error handling. The algorithm has
## also been slightly modified.

## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup.
## PKG_ADD: [~] = __all_opts__ ("fzero");

function [x, fval, info, output] = fzero (fun, x0, options = struct ())

  ## Get default options if requested.
  if (nargin == 1 && ischar (fun) && strcmp (fun, 'defaults'))
    x = optimset ("MaxIter", Inf, "MaxFunEvals", Inf, "TolX", 1e-8, \
    "OutputFcn", [], "FunValCheck", "off");
    return;
  endif

  if (nargin < 2 || nargin > 3)
    print_usage ();
  endif

  if (ischar (fun))
    fun = str2func (fun, "global");
  endif

  ## TODO
  ## displev = optimget (options, "Display", "notify");
  funvalchk = strcmpi (optimget (options, "FunValCheck", "off"), "on");
  outfcn = optimget (options, "OutputFcn");
  tolx = optimget (options, "TolX", 1e-8);
  maxiter = optimget (options, "MaxIter", Inf);
  maxfev = optimget (options, "MaxFunEvals", Inf);

  persistent mu = 0.5;

  if (funvalchk)
    ## Replace fun with a guarded version.
    fun = @(x) guarded_eval (fun, x);
  endif

  ## The default exit flag if exceeded number of iterations.
  info = 0;
  niter = 0;
  nfev = 0;

  x = fval = a = fa = b = fb = NaN;
  eps = eps (class (x0));

  ## Prepare...
  a = x0(1);
  fa = fun (a);
  nfev = 1;
  if (length (x0) > 1)
    b = x0(2);
    fb = fun (b);
    nfev += 1;
  else
    ## Try to get b.
    if (a == 0)
      aa = 1;
    else
      aa = a;
    endif
    for b = [0.9*aa, 1.1*aa, aa-1, aa+1, 0.5*aa 1.5*aa, -aa, 2*aa, -10*aa, 10*aa]
      fb = fun (b); nfev += 1;
      if (sign (fa) * sign (fb) <= 0)
        break;
      endif
    endfor
  endif

  if (b < a)
    u = a;
    a = b;
    b = u;

    fu = fa;
    fa = fb;
    fb = fu;
  endif

  if (! (sign (fa) * sign (fb) <= 0))
    error ("fzero:bracket", "fzero: not a valid initial bracketing");
  endif

  slope0 = (fb - fa) / (b - a);

  if (fa == 0)
    b = a;
    fb = fa;
  elseif (fb == 0)
    a = b;
    fa = fb;
  endif

  itype = 1;

  if (abs (fa) < abs (fb))
    u = a; fu = fa;
  else
    u = b; fu = fb;
  endif

  d = e = u;
  fd = fe = fu;
  mba = mu*(b - a);
  while (niter < maxiter && nfev < maxfev)
    switch (itype)
    case 1
      ## The initial test.
      if (b - a <= 2*(2 * abs (u) * eps + tolx))
        x = u; fval = fu;
        info = 1;
        break;
      endif
      if (abs (fa) <= 1e3*abs (fb) && abs (fb) <= 1e3*abs (fa))
        ## Secant step.
        c = u - (a - b) / (fa - fb) * fu;
      else
        ## Bisection step.
        c = 0.5*(a + b);
      endif
      d = u; fd = fu;
      itype = 5;
    case {2, 3}
      l = length (unique ([fa, fb, fd, fe]));
      if (l == 4)
        ## Inverse cubic interpolation.
        q11 = (d - e) * fd / (fe - fd);
        q21 = (b - d) * fb / (fd - fb);
        q31 = (a - b) * fa / (fb - fa);
        d21 = (b - d) * fd / (fd - fb);
        d31 = (a - b) * fb / (fb - fa);
        q22 = (d21 - q11) * fb / (fe - fb);
        q32 = (d31 - q21) * fa / (fd - fa);
        d32 = (d31 - q21) * fd / (fd - fa);
        q33 = (d32 - q22) * fa / (fe - fa);
        c = a + q31 + q32 + q33;
      endif
      if (l < 4 || sign (c - a) * sign (c - b) > 0)
        ## Quadratic interpolation + newton.
        a0 = fa;
        a1 = (fb - fa)/(b - a);
        a2 = ((fd - fb)/(d - b) - a1) / (d - a);
        ## Modification 1: this is simpler and does not seem to be worse.
        c = a - a0/a1;
        if (a2 != 0)
          c = a - a0/a1;
          for i = 1:itype
            pc = a0 + (a1 + a2*(c - b))*(c - a);
            pdc = a1 + a2*(2*c - a - b);
            if (pdc == 0)
              c = a - a0/a1;
              break;
            endif
            c -= pc/pdc;
          endfor
        endif
      endif
      itype += 1;
    case 4
      ## Double secant step.
      c = u - 2*(b - a)/(fb - fa)*fu;
      ## Bisect if too far.
      if (abs (c - u) > 0.5*(b - a))
        c = 0.5 * (b + a);
      endif
      itype = 5;
    case 5
      ## Bisection step.
      c = 0.5 * (b + a);
      itype = 2;
    endswitch

    ## Don't let c come too close to a or b.
    delta = 2*0.7*(2 * abs (u) * eps + tolx);
    if ((b - a) <= 2*delta)
      c = (a + b)/2;
    else
      c = max (a + delta, min (b - delta, c));
    endif

    ## Calculate new point.
    x = c;
    fval = fc = fun (c);
    niter ++; nfev ++;

    ## Modification 2: skip inverse cubic interpolation if
    ## nonmonotonicity is detected.
    if (sign (fc - fa) * sign (fc - fb) >= 0)
      ## The new point broke monotonicity.
      ## Disable inverse cubic.
      fe = fc;
    else
      e = d; fe = fd;
    endif

    ## Bracketing.
    if (sign (fa) * sign (fc) < 0)
      d = b; fd = fb;
      b = c; fb = fc;
    elseif (sign (fb) * sign (fc) < 0)
      d = a; fd = fa;
      a = c; fa = fc;
    elseif (fc == 0)
      a = b = c; fa = fb = fc;
      info = 1;
      break;
    else
      ## This should never happen.
      error ("fzero:bracket", "fzero: zero point is not bracketed");
    endif

    ## If there's an output function, use it now.
    if (outfcn)
      optv.funccount = nfev;
      optv.fval = fval;
      optv.iteration = niter;
      if (outfcn (x, optv, "iter"))
        info = -1;
        break;
      endif
    endif

    if (abs (fa) < abs (fb))
      u = a; fu = fa;
    else
      u = b; fu = fb;
    endif
    if (b - a <= 2*(2 * abs (u) * eps + tolx))
      info = 1;
      break;
    endif

    ## Skip bisection step if successful reduction.
    if (itype == 5 && (b - a) <= mba)
      itype = 2;
    endif
    if (itype == 2)
      mba = mu * (b - a);
    endif
  endwhile

  ## Check solution for a singularity by examining slope
  if (info == 1)
    if ((b - a) != 0 && abs ((fb - fa)/(b - a) / slope0) > max (1e6, 0.5/(eps+tolx)))
      info = -5;
    endif
  endif

  output.iterations = niter;
  output.funcCount = nfev;
  output.bracketx = [a, b];
  output.brackety = [fa, fb];

endfunction

## An assistant function that evaluates a function handle and checks for
## bad results.
function fx = guarded_eval (fun, x)
  fx = fun (x);
  fx = fx(1);
  if (! isreal (fx))
    error ("fzero:notreal", "fzero: non-real value encountered");
  elseif (isnan (fx))
    error ("fzero:isnan", "fzero: NaN value encountered");
  endif
endfunction

%!shared opt0
%! opt0 = optimset ("tolx", 0);
%!assert(fzero(@cos, [0, 3], opt0), pi/2, 10*eps)
%!assert(fzero(@(x) x^(1/3) - 1e-8, [0,1], opt0), 1e-24, 1e-22*eps)
*/

//======== std() ===================================================================================
/*
## Copyright (C) 1996-2012 John W. Eaton
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn  {Function File} {} std (@var{x})
## @deftypefnx {Function File} {} std (@var{x}, @var{opt})
## @deftypefnx {Function File} {} std (@var{x}, @var{opt}, @var{dim})
## Compute the standard deviation of the elements of the vector @var{x}.
## @tex
## $$
## {\rm std} (x) = \sigma = \sqrt{{\sum_{i=1}^N (x_i - \bar{x})^2 \over N - 1}}
## $$
## where $\bar{x}$ is the mean value of $x$ and $N$ is the number of elements.
## @end tex
## @ifnottex
##
## @example
## @group
## std (x) = sqrt ( 1/(N-1) SUM_i (x(i) - mean(x))^2 )
## @end group
## @end example
##
## @noindent
## where @math{N} is the number of elements.
## @end ifnottex
##
## If @var{x} is a matrix, compute the standard deviation for
## each column and return them in a row vector.
##
## The argument @var{opt} determines the type of normalization to use.
## Valid values are
##
## @table @asis
## @item 0:
##   normalize with @math{N-1}, provides the square root of the best unbiased
## estimator of the variance [default]
##
## @item 1:
##   normalize with @math{N}, this provides the square root of the second
## moment around the mean
## @end table
##
## If the optional argument @var{dim} is given, operate along this dimension.
## @seealso{var, range, iqr, mean, median}
## @end deftypefn

## Author: jwe

function retval = std (x, opt = 0, dim)

  if (nargin < 1 || nargin > 3)
    print_usage ();
  endif

  if (! (isnumeric (x) || islogical (x)))
    error ("std: X must be a numeric vector or matrix");
  endif

  if (isempty (opt))
    opt = 0;
  endif
  if (opt != 0 && opt != 1)
    error ("std: normalization OPT must be 0 or 1");
  endif

  nd = ndims (x);
  sz = size (x);
  if (nargin < 3)
    ## Find the first non-singleton dimension.
    (dim = find (sz > 1, 1)) || (dim = 1);
  else
    if (!(isscalar (dim) && dim == fix (dim))
        || !(1 <= dim && dim <= nd))
      error ("std: DIM must be an integer and a valid dimension");
    endif
  endif

  n = sz(dim);
  if (n == 1 || isempty (x))
    if (isa (x, 'single'))
      retval = zeros (sz, 'single');
    else
      retval = zeros (sz);
    endif
  else
    retval = sqrt (sumsq (center (x, dim), dim) / (n - 1 + opt));
  endif

endfunction


%!test
%! x = ones (10, 2);
%! y = [1, 3];
%! assert(std (x) == [0, 0]);
%! assert(std (y), sqrt (2), sqrt (eps));
%! assert(std (x, 0, 2), zeros (10, 1));

%!assert(std (ones (3, 1, 2), 0, 2), zeros (3, 1, 2));
%!assert(std ([1 2], 0), sqrt(2)/2, 5*eps);
%!assert(std ([1 2], 1), 0.5, 5*eps);
%!assert(std(1), 0);
%!assert(std(single(1)), single(0));
%!assert(std([]), []);
%!assert(std(ones (1,3,0,2)), ones (1,3,0,2));

%% Test input validation
%!error std ();
%!error std (1, 2, 3, 4);
%!error std (['A'; 'B'])
%!error std (1, -1);

*/

//======== mean() ==================================================================================

/*
## Copyright (C) 1995-2012 Kurt Hornik
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn  {Function File} {} mean (@var{x})
## @deftypefnx {Function File} {} mean (@var{x}, @var{dim})
## @deftypefnx {Function File} {} mean (@var{x}, @var{opt})
## @deftypefnx {Function File} {} mean (@var{x}, @var{dim}, @var{opt})
## Compute the mean of the elements of the vector @var{x}.
## @tex
## $$ {\rm mean}(x) = \bar{x} = {1\over N} \sum_{i=1}^N x_i $$
## @end tex
## @ifnottex
##
## @example
## mean (x) = SUM_i x(i) / N
## @end example
##
## @end ifnottex
## If @var{x} is a matrix, compute the mean for each column and return them
## in a row vector.
##
## The optional argument @var{opt} selects the type of mean to compute.
## The following options are recognized:
##
## @table @asis
## @item "a"
## Compute the (ordinary) arithmetic mean.  [default]
##
## @item "g"
## Compute the geometric mean.
##
## @item "h"
## Compute the harmonic mean.
## @end table
##
## If the optional argument @var{dim} is given, operate along this dimension.
##
## Both @var{dim} and @var{opt} are optional.  If both are supplied,
## either may appear first.
## @seealso{median, mode}
## @end deftypefn

## Author: KH <Kurt.Hornik@wu-wien.ac.at>
## Description: Compute arithmetic, geometric, and harmonic mean

function y = mean (x, opt1, opt2)

  if (nargin < 1 || nargin > 3)
    print_usage ();
  endif

  if (! (isnumeric (x) || islogical (x)))
    error ("mean: X must be a numeric vector or matrix");
  endif

  need_dim = false;

  if (nargin == 1)
    opt = "a";
    need_dim = true;
  elseif (nargin == 2)
    if (ischar (opt1))
      opt = opt1;
      need_dim = true;
    else
      dim = opt1;
      opt = "a";
    endif
  elseif (nargin == 3)
    if (ischar (opt1))
      opt = opt1;
      dim = opt2;
    elseif (ischar (opt2))
      opt = opt2;
      dim = opt1;
    else
      error ("mean: OPT must be a string");
    endif
  else
    print_usage ();
  endif

  nd = ndims (x);
  sz = size (x);
  if (need_dim)
    ## Find the first non-singleton dimension.
    (dim = find (sz > 1, 1)) || (dim = 1);
  else
    if (!(isscalar (dim) && dim == fix (dim))
      || !(1 <= dim && dim <= nd))
      error ("mean: DIM must be an integer and a valid dimension");
    endif
  endif

  n = sz(dim);

  if (strcmp (opt, "a"))
    y = sum (x, dim) / n;
  elseif (strcmp (opt, "g"))
    y = prod (x, dim) .^ (1/n);
  elseif (strcmp (opt, "h"))
    y = n ./ sum (1 ./ x, dim);
  else
    error ("mean: option '%s' not recognized", opt);
  endif

endfunction


%!test
%! x = -10:10;
%! y = x';
%! z = [y, y+10];
%! assert(mean (x) == 0);
%! assert(mean (y) == 0);
%! assert(mean (z) == [0, 10]);

%!assert(mean (magic(3), 1), [5, 5, 5]);
%!assert(mean (magic(3), 2), [5; 5; 5]);
%!assert(mean ([2 8], 'g'), 4);
%!assert(mean ([4 4 2], 'h'), 3);
%!assert(mean (logical ([1 0 1 1])), 0.75);
%!assert(mean (single ([1 0 1 1])), single (0.75));

%% Test input validation
%!error mean ();
%!error mean (1, 2, 3, 4);
%!error mean ({1:5});
%!error mean (1, 2, 3);
%!error mean (1, ones(2,2));
%!error mean (1, 1.5);
%!error mean (1, 0);
%!error mean (1, 3);
%!error mean (1, 'b');

*/

//======== gampdf() ================================================================================

/*

## Copyright (C) 2012 Rik Wehbring
## Copyright (C) 1995-2012 Kurt Hornik
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn {Function File} {} gampdf (@var{x}, @var{a}, @var{b})
## For each element of @var{x}, return the probability density function
## (PDF) at @var{x} of the Gamma distribution with shape parameter
## @var{a} and scale @var{b}.
## @end deftypefn

## Author: TT <Teresa.Twaroch@ci.tuwien.ac.at>
## Description: PDF of the Gamma distribution

function pdf = gampdf (x, a, b)

  if (nargin != 3)
    print_usage ();
  endif

  if (!isscalar (a) || !isscalar (b))
    [retval, x, a, b] = common_size (x, a, b);
    if (retval > 0)
      error ("gampdf: X, A, and B must be of common size or scalars");
    endif
  endif

  if (iscomplex (x) || iscomplex (a) || iscomplex (b))
    error ("gampdf: X, A, and B must not be complex");
  endif

  if (isa (x, "single") || isa (a, "single") || isa (b, "single"))
    pdf = zeros (size (x), "single");
  else
    pdf = zeros (size (x));
  endif

  k = !(a > 0) | !(b > 0) | isnan (x);
  pdf(k) = NaN;

  k = (x >= 0) & (a > 0) & (a <= 1) & (b > 0);
  if (isscalar (a) && isscalar (b))
    pdf(k) = (x(k) .^ (a - 1)) ...
              .* exp (- x(k) / b) / gamma (a) / (b ^ a);
  else
    pdf(k) = (x(k) .^ (a(k) - 1)) ...
              .* exp (- x(k) ./ b(k)) ./ gamma (a(k)) ./ (b(k) .^ a(k));
  endif

  k = (x >= 0) & (a > 1) & (b > 0);
  if (isscalar (a) && isscalar (b))
    pdf(k) = exp (- a * log (b) + (a-1) * log (x(k))
                  - x(k) / b - gammaln (a));
  else
    pdf(k) = exp (- a(k) .* log (b(k)) + (a(k)-1) .* log (x(k))
                  - x(k) ./ b(k) - gammaln (a(k)));
  endif

endfunction


%!shared x,y
%! x = [-1 0 0.5 1 Inf];
%! y = [0 exp(-x(2:end))];
%!assert(gampdf (x, ones(1,5), ones(1,5)), y);
%!assert(gampdf (x, 1, ones(1,5)), y);
%!assert(gampdf (x, ones(1,5), 1), y);
%!assert(gampdf (x, [0 -Inf NaN Inf 1], 1), [NaN NaN NaN NaN y(5)]);
%!assert(gampdf (x, 1, [0 -Inf NaN Inf 1]), [NaN NaN NaN 0 y(5)]);
%!assert(gampdf ([x, NaN], 1, 1), [y, NaN]);

%% Test class of input preserved
%!assert(gampdf (single([x, NaN]), 1, 1), single([y, NaN]));
%!assert(gampdf ([x, NaN], single(1), 1), single([y, NaN]));
%!assert(gampdf ([x, NaN], 1, single(1)), single([y, NaN]));

%% Test input validation
%!error gampdf ()
%!error gampdf (1)
%!error gampdf (1,2)
%!error gampdf (1,2,3,4)
%!error gampdf (ones(3),ones(2),ones(2))
%!error gampdf (ones(2),ones(3),ones(2))
%!error gampdf (ones(2),ones(2),ones(3))
%!error gampdf (i, 2, 2)
%!error gampdf (2, i, 2)
%!error gampdf (2, 2, i)

*/

//======== normpdf() ===============================================================================

/*
## Copyright (C) 2012 Rik Wehbring
## Copyright (C) 1995-2012 Kurt Hornik
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn  {Function File} {} normpdf (@var{x})
## @deftypefnx {Function File} {} normpdf (@var{x}, @var{mu}, @var{sigma})
## For each element of @var{x}, compute the probability density function
## (PDF) at @var{x} of the normal distribution with mean @var{mu} and
## standard deviation @var{sigma}.
##
## Default values are @var{mu} = 0, @var{sigma} = 1.
## @end deftypefn

## Author: TT <Teresa.Twaroch@ci.tuwien.ac.at>
## Description: PDF of the normal distribution

function pdf = normpdf (x, mu = 0, sigma = 1)

  if (nargin != 1 && nargin != 3)
    print_usage ();
  endif

  if (!isscalar (mu) || !isscalar (sigma))
    [retval, x, mu, sigma] = common_size (x, mu, sigma);
    if (retval > 0)
      error ("normpdf: X, MU, and SIGMA must be of common size or scalars");
    endif
  endif

  if (iscomplex (x) || iscomplex (mu) || iscomplex (sigma))
    error ("normpdf: X, MU, and SIGMA must not be complex");
  endif

  if (isa (x, "single") || isa (mu, "single") || isa (sigma, "single"))
    pdf = zeros (size (x), "single");
  else
    pdf = zeros (size (x));
  endif

  if (isscalar (mu) && isscalar (sigma))
    if (!isinf (mu) && !isnan (mu) && (sigma > 0) && (sigma < Inf))
      pdf = stdnormal_pdf ((x - mu) / sigma) / sigma;
    else
      pdf = NaN (size (x), class (pdf));
    endif
  else
    k = isinf (mu) | !(sigma > 0) | !(sigma < Inf);
    pdf(k) = NaN;

    k = !isinf (mu) & (sigma > 0) & (sigma < Inf);
    pdf(k) = stdnormal_pdf ((x(k) - mu(k)) ./ sigma(k)) ./ sigma(k);
  endif

endfunction


%!shared x,y
%! x = [-Inf 1 2 Inf];
%! y = 1/sqrt(2*pi)*exp (-(x-1).^2/2);
%!assert(normpdf (x, ones(1,4), ones(1,4)), y);
%!assert(normpdf (x, 1, ones(1,4)), y);
%!assert(normpdf (x, ones(1,4), 1), y);
%!assert(normpdf (x, [0 -Inf NaN Inf], 1), [y(1) NaN NaN NaN]);
%!assert(normpdf (x, 1, [Inf NaN -1 0]), [NaN NaN NaN NaN]);
%!assert(normpdf ([x, NaN], 1, 1), [y, NaN]);

%% Test class of input preserved
%!assert(normpdf (single([x, NaN]), 1, 1), single([y, NaN]), eps("single"));
%!assert(normpdf ([x, NaN], single(1), 1), single([y, NaN]), eps("single"));
%!assert(normpdf ([x, NaN], 1, single(1)), single([y, NaN]), eps("single"));

%% Test input validation
%!error normpdf ()
%!error normpdf (1,2)
%!error normpdf (1,2,3,4)
%!error normpdf (ones(3),ones(2),ones(2))
%!error normpdf (ones(2),ones(3),ones(2))
%!error normpdf (ones(2),ones(2),ones(3))
%!error normpdf (i, 2, 2)
%!error normpdf (2, i, 2)
%!error normpdf (2, 2, i)

*/

//======== stdnormal_pdf() =========================================================================

/*
## Copyright (C) 2012 Rik Wehbring
## Copyright (C) 1995-2012 Kurt Hornik
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn {Function File} {} stdnormal_pdf (@var{x})
## For each element of @var{x}, compute the probability density function
## (PDF) at @var{x} of the standard normal distribution (mean = 0,
## standard deviation = 1).
## @end deftypefn

## Author: TT <Teresa.Twaroch@ci.tuwien.ac.at>
## Description: PDF of the standard normal distribution

function pdf = stdnormal_pdf (x)

  if (nargin != 1)
    print_usage ();
  endif

  if (iscomplex (x))
    error ("stdnormal_pdf: X must not be complex");
  endif

  pdf = (2 * pi)^(- 1/2) * exp (- x .^ 2 / 2);

endfunction


%!shared x,y
%! x = [-Inf 0 1 Inf];
%! y = 1/sqrt(2*pi)*exp (-x.^2/2);
%!assert(stdnormal_pdf ([x, NaN]), [y, NaN], eps);

%% Test class of input preserved
%!assert(stdnormal_pdf (single([x, NaN])), single([y, NaN]), eps("single"));

%% Test input validation
%!error stdnormal_pdf ()
%!error stdnormal_pdf (1,2)
%!error stdnormal_pdf (i)
*/



















