/* statlib.c -- Statistical functions for testing the randomness of
number sequences. */
/*
Copyright 1999 , 2000 Free Software Foundation , Inc .
This file is part of the GNU MP Library test suite .
The GNU MP Library test suite 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 .
The GNU MP Library test suite 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
the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
/* The theories for these functions are taken from D. Knuth's "The Art
of Computer Programming : Volume 2 , Seminumerical Algorithms " , Third
Edition, Addison Wesley, 1998. */
/* Implementation notes.
The Kolmogorov - Smirnov test .
Eq . ( 13 ) in Knuth , p . 50 , says that if X1 , X2 , . . . , Xn are independent
observations arranged into ascending order
Kp = sqr ( n ) * max ( j / n - F ( Xj ) ) for all 1 < = j < = n
Km = sqr ( n ) * max ( F ( Xj ) - ( j - 1 ) / n ) ) for all 1 < = j < = n
where F ( x ) = Pr ( X < = x ) = probability that ( X < = x ) , which for a
uniformly distributed random real number between zero and one is
exactly the number itself ( x ) .
The answer to exercise 23 gives the following implementation , which
doesn ' t need the observations to be sorted in ascending order :
for ( k = 0 ; k < m ; k + + )
a [ k ] = 1 . 0
b [ k ] = 0 . 0
c [ k ] = 0
for ( each observation Xj )
Y = F ( Xj )
k = floor ( m * Y )
a [ k ] = min ( a [ k ] , Y )
b [ k ] = max ( b [ k ] , Y )
c [ k ] + = 1
j = 0
rp = rm = 0
for ( k = 0 ; k < m ; k + + )
if ( c [ k ] > 0 )
rm = max ( rm , a [ k ] - j / n )
j + = c [ k ]
rp = max ( rp , j / n - b [ k ] )
Kp = sqr ( n ) * rp
Km = sqr ( n ) * rm
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "gmpstat.h"
/* ks (Kp, Km, X, P, n) -- Perform a Kolmogorov-Smirnov test on the N
real numbers between zero and one in vector X . P is the
distribution function , called for each entry in X , which should
calculate the probability of X being greater than or equal to any
number in the sequence . ( For a uniformly distributed sequence of
real numbers between zero and one , this is simply equal to X . ) The
result is put in Kp and Km. */
void
ks (mpf_t Kp,
mpf_t Km,
mpf_t X[],
void (P) (mpf_t, mpf_t),
unsigned long int n)
{
mpf_t Kt;
/* temp */
mpf_t f_x;
mpf_t f_j;
/* j */
mpf_t f_jnq;
/* j/n or (j-1)/n */
unsigned long int j;
/* Sort the vector in ascending order. */
qsort (X, n,
sizeof (__mpf_struct), mpf_cmp);
/* K-S test. */
/* Kp = sqr(n) * max(j/n - F(Xj)) for all 1<=j<=n
Km = sqr ( n ) * max ( F ( Xj ) - ( j - 1 ) / n ) ) for all 1 < = j < = n
*/
mpf_init (Kt); mpf_init (f_x); mpf_init (f_j); mpf_init (f_jnq);
mpf_set_ui (Kp,
0 ); mpf_set_ui (Km,
0 );
for (j =
1 ; j <= n; j++)
{
P (f_x, X[j-
1 ]);
mpf_set_ui (f_j, j);
mpf_div_ui (f_jnq, f_j, n);
mpf_sub (Kt, f_jnq, f_x);
if (mpf_cmp (Kt, Kp) >
0 )
mpf_set (Kp, Kt);
if (g_debug > DEBUG_2)
{
printf (
"j=%lu " , j);
printf (
"P()=" ); mpf_out_str (stdout,
10 ,
2 , f_x); printf (
"\t" );
printf (
"jnq=" ); mpf_out_str (stdout,
10 ,
2 , f_jnq); printf (
" " );
printf (
"diff=" ); mpf_out_str (stdout,
10 ,
2 , Kt); printf (
" " );
printf (
"Kp=" ); mpf_out_str (stdout,
10 ,
2 , Kp); printf (
"\t" );
}
mpf_sub_ui (f_j, f_j,
1 );
mpf_div_ui (f_jnq, f_j, n);
mpf_sub (Kt, f_x, f_jnq);
if (mpf_cmp (Kt, Km) >
0 )
mpf_set (Km, Kt);
if (g_debug > DEBUG_2)
{
printf (
"jnq=" ); mpf_out_str (stdout,
10 ,
2 , f_jnq); printf (
" " );
printf (
"diff=" ); mpf_out_str (stdout,
10 ,
2 , Kt); printf (
" " );
printf (
"Km=" ); mpf_out_str (stdout,
10 ,
2 , Km); printf (
" " );
printf (
"\n" );
}
}
mpf_sqrt_ui (Kt, n);
mpf_mul (Kp, Kp, Kt);
mpf_mul (Km, Km, Kt);
mpf_clear (Kt); mpf_clear (f_x); mpf_clear (f_j); mpf_clear (f_jnq);
}
/* ks_table(val, n) -- calculate probability for Kp/Km less than or
equal to VAL with N observations. See [Knuth section 3.3.1] */
void
ks_table (mpf_t p, mpf_t val,
const unsigned int n)
{
/* We use Eq. (27), Knuth p.58, skipping O(1/n) for simplicity.
This shortcut will result in too high probabilities , especially
when n is small .
Pr(Kp(n) <= s) = 1 - pow(e, -2*s^2) * (1 - 2/3*s/sqrt(n) + O(1/n)) */
/* We have 's' in variable VAL and store the result in P. */
mpf_t t1, t2;
mpf_init (t1); mpf_init (t2);
/* t1 = 1 - 2/3 * s/sqrt(n) */
mpf_sqrt_ui (t1, n);
mpf_div (t1, val, t1);
mpf_mul_ui (t1, t1,
2 );
mpf_div_ui (t1, t1,
3 );
mpf_ui_sub (t1,
1 , t1);
/* t2 = pow(e, -2*s^2) */
#ifndef OLDGMP
mpf_pow_ui (t2, val,
2 );
/* t2 = s^2 */
mpf_set_d (t2, exp (-(
2 .
0 * mpf_get_d (t2))));
#else
/* hmmm, gmp doesn't have pow() for floats. use doubles. */
mpf_set_d (t2, pow (M_E, -(
2 * pow (mpf_get_d (val),
2 ))));
#endif
/* p = 1 - t1 * t2 */
mpf_mul (t1, t1, t2);
mpf_ui_sub (p,
1 , t1);
mpf_clear (t1); mpf_clear (t2);
}
static double x2_table_X[][
7 ] = {
{ -
2 .
33 , -
1 .
64 , -.
674 ,
0 .
0 ,
0 .
674 ,
1 .
64 ,
2 .
33 },
/* x */
{
5 .
4289 ,
2 .
6896 , .
454276 ,
0 .
0 , .
454276 ,
2 .
6896 ,
5 .
4289 }
/* x^2 */
};
#define _
2 D3 ((
double ) .
6666666666 )
/* x2_table (t, v, n) -- return chi-square table row for V in T[]. */
void
x2_table (
double t[],
unsigned int v)
{
int f;
/* FIXME: Do a table lookup for v <= 30 since the following formula
[Knuth, vol 2, 3.3.1] is only good for v > 30. */
/* value = v + sqrt(2*v) * X[p] + (2/3) * X[p]^2 - 2/3 + O(1/sqrt(t) */
/* NOTE: The O() term is ignored for simplicity. */
for (f =
0 ; f <
7 ; f++)
t[f] =
v +
sqrt (
2 * v) * x2_table_X[
0 ][f] +
_
2 D3 * x2_table_X[
1 ][f] - _
2 D3;
}
/* P(p, x) -- Distribution function. Calculate the probability of X
being greater than or equal to any number in the sequence . For a
random real number between zero and one given by a uniformly
distributed random number generator, this is simply equal to X. */
static void
P (mpf_t p, mpf_t x)
{
mpf_set (p, x);
}
/* mpf_freqt() -- Frequency test using KS on N real numbers between zero
and one. See [Knuth vol 2, p.61]. */
void
mpf_freqt (mpf_t Kp,
mpf_t Km,
mpf_t X[],
const unsigned long int n)
{
ks (Kp, Km, X, P, n);
}
/* The Chi-square test. Eq. (8) in Knuth vol. 2 says that if Y[]
holds the observations and p [ ] is the probability for . . ( to be
continued ! )
V = 1/n * sum((s=1 to k) Y[s]^2 / p[s]) - n */
void
x2 (mpf_t V,
/* result */
unsigned long int X[],
/* data */
unsigned int k,
/* #of categories */
void (P) (mpf_t,
unsigned long int ,
void *),
/* probability func */
void *x,
/* extra user data passed to P() */
unsigned long int n)
/* #of samples */
{
unsigned int f;
mpf_t f_t, f_t2;
/* temp floats */
mpf_init (f_t); mpf_init (f_t2);
mpf_set_ui (V,
0 );
for (f =
0 ; f < k; f++)
{
if (g_debug > DEBUG_2)
fprintf (stderr,
"%u: P()=" , f);
mpf_set_ui (f_t, X[f]);
mpf_mul (f_t, f_t, f_t);
/* f_t = X[f]^2 */
P (f_t2, f, x);
/* f_t2 = Pr(f) */
if (g_debug > DEBUG_2)
mpf_out_str (stderr,
10 ,
2 , f_t2);
mpf_div (f_t, f_t, f_t2);
mpf_add (V, V, f_t);
if (g_debug > DEBUG_2)
{
fprintf (stderr,
"\tV=" );
mpf_out_str (stderr,
10 ,
2 , V);
fprintf (stderr,
"\t" );
}
}
if (g_debug > DEBUG_2)
fprintf (stderr,
"\n" );
mpf_div_ui (V, V, n);
mpf_sub_ui (V, V, n);
mpf_clear (f_t); mpf_clear (f_t2);
}
/* Pzf(p, s, x) -- Probability for category S in mpz_freqt(). It's
1/d for all S. X is a pointer to an unsigned int holding 'd'. */
static void
Pzf (mpf_t p,
unsigned long int s,
void *x)
{
mpf_set_ui (p,
1 );
mpf_div_ui (p, p, *((
unsigned int *) x));
}
/* mpz_freqt(V, X, imax, n) -- Frequency test on integers. [Knuth,
vol 2 , 3 . 3 . 2 ] . Keep IMAX low on this one , since we loop from 0 to
IMAX . 128 or 256 could be nice .
X [ ] must not contain numbers outside the range 0 < = X < = IMAX .
Return value is number of observations actually used , after
discarding entries out of range .
Since X [ ] contains integers between zero and IMAX , inclusive , we
have IMAX + 1 categories .
Note that N should be at least 5 * IMAX . Result is put in V and can
be compared to output from x2_table (v=IMAX). */
unsigned long int
mpz_freqt (mpf_t V,
mpz_t X[],
unsigned int imax,
const unsigned long int n)
{
unsigned long int *v;
/* result */
unsigned int f;
unsigned int d;
/* number of categories = imax+1 */
unsigned int uitemp;
unsigned long int usedn;
d = imax +
1 ;
v = (
unsigned long int *) calloc (imax +
1 ,
sizeof (
unsigned long int ));
if (NULL == v)
{
fprintf (stderr,
"mpz_freqt(): out of memory\n" );
exit (
1 );
}
/* count */
usedn = n;
/* actual number of observations */
for (f =
0 ; f < n; f++)
{
uitemp = mpz_get_ui(X[f]);
if (uitemp > imax)
/* sanity check */
{
if (g_debug)
fprintf (stderr,
"mpz_freqt(): warning: input insanity: %u, " \
"ignored.\n" , uitemp);
usedn--;
continue ;
}
v[uitemp]++;
}
if (g_debug > DEBUG_2)
{
fprintf (stderr,
"counts:\n" );
for (f =
0 ; f <= imax; f++)
fprintf (stderr,
"%u:\t%lu\n" , f, v[f]);
}
/* chi-square with k=imax+1 and P(x)=1/(imax+1) for all x.*/
x2 (V, v, d, Pzf, (
void *) &d, usedn);
free (v);
return (usedn);
}
/* debug dummy to drag in dump funcs */
void
foo_debug ()
{
if (
0 )
{
mpf_dump (
0 );
#ifndef OLDGMP
mpz_dump (
0 );
#endif
}
}
/* merit (rop, t, v, m) -- calculate merit for spectral test result in
dimension T , see Knuth p . 105 . BUGS : Only valid for 2 < = T < =
6. */
void
merit (mpf_t rop,
unsigned int t, mpf_t v, mpz_t m)
{
int f;
mpf_t f_m, f_const, f_pi;
mpf_init (f_m);
mpf_set_z (f_m, m);
mpf_init_set_d (f_const, M_PI);
mpf_init_set_d (f_pi, M_PI);
switch (t)
{
case 2 :
/* PI */
break ;
case 3 :
/* PI * 4/3 */
mpf_mul_ui (f_const, f_const,
4 );
mpf_div_ui (f_const, f_const,
3 );
break ;
case 4 :
/* PI^2 * 1/2 */
mpf_mul (f_const, f_const, f_pi);
mpf_div_ui (f_const, f_const,
2 );
break ;
case 5 :
/* PI^2 * 8/15 */
mpf_mul (f_const, f_const, f_pi);
mpf_mul_ui (f_const, f_const,
8 );
mpf_div_ui (f_const, f_const,
15 );
break ;
case 6 :
/* PI^3 * 1/6 */
mpf_mul (f_const, f_const, f_pi);
mpf_mul (f_const, f_const, f_pi);
mpf_div_ui (f_const, f_const,
6 );
break ;
default :
fprintf (stderr,
"spect (merit): can't calculate merit for dimensions > 6\n" );
mpf_set_ui (f_const,
0 );
break ;
}
/* rop = v^t */
mpf_set (rop, v);
for (f =
1 ; f < t; f++)
mpf_mul (rop, rop, v);
mpf_mul (rop, rop, f_const);
mpf_div (rop, rop, f_m);
mpf_clear (f_m);
mpf_clear (f_const);
mpf_clear (f_pi);
}
double
merit_u (
unsigned int t, mpf_t v, mpz_t m)
{
mpf_t rop;
double res;
mpf_init (rop);
merit (rop, t, v, m);
res = mpf_get_d (rop);
mpf_clear (rop);
return res;
}
/* f_floor (rop, op) -- Set rop = floor (op). */
void
f_floor (mpf_t rop, mpf_t op)
{
mpz_t z;
mpz_init (z);
/* No mpf_floor(). Convert to mpz and back. */
mpz_set_f (z, op);
mpf_set_z (rop, z);
mpz_clear (z);
}
/* vz_dot (rop, v1, v2, nelem) -- compute dot product of z-vectors V1,
V2. N is number of elements in vectors V1 and V2. */
void
vz_dot (mpz_t rop, mpz_t V1[], mpz_t V2[],
unsigned int n)
{
mpz_t t;
mpz_init (t);
mpz_set_ui (rop,
0 );
while (n--)
{
mpz_mul (t, V1[n], V2[n]);
mpz_add (rop, rop, t);
}
mpz_clear (t);
}
void
spectral_test (mpf_t rop[],
unsigned int T, mpz_t a, mpz_t m)
{
/* Knuth "Seminumerical Algorithms, Third Edition", section 3.3.4
(pp. 101-103). */
/* v[t] = min { sqrt (x[1]^2 + ... + x[t]^2) |
x[1] + a*x[2] + ... + pow (a, t-1) * x[t] is congruent to 0 (mod m) } */
/* Variables. */
unsigned int ui_t;
unsigned int ui_i, ui_j, ui_k, ui_l;
mpf_t f_tmp1, f_tmp2;
mpz_t tmp1, tmp2, tmp3;
mpz_t U[GMP_SPECT_MAXT][GMP_SPECT_MAXT],
V[GMP_SPECT_MAXT][GMP_SPECT_MAXT],
X[GMP_SPECT_MAXT],
Y[GMP_SPECT_MAXT],
Z[GMP_SPECT_MAXT];
mpz_t h, hp, r, s, p, pp, q, u, v;
/* GMP inits. */
mpf_init (f_tmp1);
mpf_init (f_tmp2);
for (ui_i =
0 ; ui_i < GMP_SPECT_MAXT; ui_i++)
{
for (ui_j =
0 ; ui_j < GMP_SPECT_MAXT; ui_j++)
{
mpz_init_set_ui (U[ui_i][ui_j],
0 );
mpz_init_set_ui (V[ui_i][ui_j],
0 );
}
mpz_init_set_ui (X[ui_i],
0 );
mpz_init_set_ui (Y[ui_i],
0 );
mpz_init (Z[ui_i]);
}
mpz_init (tmp1);
mpz_init (tmp2);
mpz_init (tmp3);
mpz_init (h);
mpz_init (hp);
mpz_init (r);
mpz_init (s);
mpz_init (p);
mpz_init (pp);
mpz_init (q);
mpz_init (u);
mpz_init (v);
/* Implementation inits. */
if (T > GMP_SPECT_MAXT)
T = GMP_SPECT_MAXT;
/* FIXME: Lazy. */
/* S1 [Initialize.] */
ui_t =
2 -
1 ;
/* NOTE: `t' in description == ui_t + 1
for easy indexing */
mpz_set (h, a);
mpz_set (hp, m);
mpz_set_ui (p,
1 );
mpz_set_ui (pp,
0 );
mpz_set (r, a);
mpz_pow_ui (s, a,
2 );
mpz_add_ui (s, s,
1 );
/* s = 1 + a^2 */
/* S2 [Euclidean step.] */
while (
1 )
{
if (g_debug > DEBUG_1)
{
mpz_mul (tmp1, h, pp);
mpz_mul (tmp2, hp, p);
mpz_sub (tmp1, tmp1, tmp2);
if (mpz_cmpabs (m, tmp1))
{
printf (
"***BUG***: h*pp - hp*p = " );
mpz_out_str (stdout,
10 , tmp1);
printf (
"\n" );
}
}
if (g_debug > DEBUG_2)
{
printf (
"hp = " );
mpz_out_str (stdout,
10 , hp);
printf (
"\nh = " );
mpz_out_str (stdout,
10 , h);
printf (
"\n" );
fflush (stdout);
}
if (mpz_sgn (h))
mpz_tdiv_q (q, hp, h);
/* q = floor(hp/h) */
else
mpz_set_ui (q,
1 );
if (g_debug > DEBUG_2)
{
printf (
"q = " );
mpz_out_str (stdout,
10 , q);
printf (
"\n" );
fflush (stdout);
}
mpz_mul (tmp1, q, h);
mpz_sub (u, hp, tmp1);
/* u = hp - q*h */
mpz_mul (tmp1, q, p);
mpz_sub (v, pp, tmp1);
/* v = pp - q*p */
mpz_pow_ui (tmp1, u,
2 );
mpz_pow_ui (tmp2, v,
2 );
mpz_add (tmp1, tmp1, tmp2);
if (mpz_cmp (tmp1, s) <
0 )
{
mpz_set (s, tmp1);
/* s = u^2 + v^2 */
mpz_set (hp, h);
/* hp = h */
mpz_set (h, u);
/* h = u */
mpz_set (pp, p);
/* pp = p */
mpz_set (p, v);
/* p = v */
}
else
break ;
}
/* S3 [Compute v2.] */
mpz_sub (u, u, h);
mpz_sub (v, v, p);
mpz_pow_ui (tmp1, u,
2 );
mpz_pow_ui (tmp2, v,
2 );
mpz_add (tmp1, tmp1, tmp2);
if (mpz_cmp (tmp1, s) <
0 )
{
mpz_set (s, tmp1);
/* s = u^2 + v^2 */
mpz_set (hp, u);
mpz_set (pp, v);
}
mpf_set_z (f_tmp1, s);
mpf_sqrt (rop[ui_t -
1 ], f_tmp1);
/* S4 [Advance t.] */
mpz_neg (U[
0 ][
0 ], h);
mpz_set (U[
0 ][
1 ], p);
mpz_neg (U[
1 ][
0 ], hp);
mpz_set (U[
1 ][
1 ], pp);
mpz_set (V[
0 ][
0 ], pp);
mpz_set (V[
0 ][
1 ], hp);
mpz_neg (V[
1 ][
0 ], p);
mpz_neg (V[
1 ][
1 ], h);
if (mpz_cmp_ui (pp,
0 ) >
0 )
{
mpz_neg (V[
0 ][
0 ], V[
0 ][
0 ]);
mpz_neg (V[
0 ][
1 ], V[
0 ][
1 ]);
mpz_neg (V[
1 ][
0 ], V[
1 ][
0 ]);
mpz_neg (V[
1 ][
1 ], V[
1 ][
1 ]);
}
while (ui_t +
1 != T)
/* S4 loop */
{
ui_t++;
mpz_mul (r, a, r);
mpz_mod (r, r, m);
/* Add new row and column to U and V. They are initialized with
all elements set to zero, so clearing is not necessary. */
mpz_neg (U[ui_t][
0 ], r);
/* U: First col in new row. */
mpz_set_ui (U[ui_t][ui_t],
1 );
/* U: Last col in new row. */
mpz_set (V[ui_t][ui_t], m);
/* V: Last col in new row. */
/* "Finally, for 1 <= i < t,
set q = round ( vi1 * r / m ) ,
vit = vi1 * r - q * m ,
and Ut=Ut+q*Ui */
for (ui_i =
0 ; ui_i < ui_t; ui_i++)
{
mpz_mul (tmp1, V[ui_i][
0 ], r);
/* tmp1=vi1*r */
zdiv_round (q, tmp1, m);
/* q=round(vi1*r/m) */
mpz_mul (tmp2, q, m);
/* tmp2=q*m */
mpz_sub (V[ui_i][ui_t], tmp1, tmp2);
for (ui_j =
0 ; ui_j <= ui_t; ui_j++)
/* U[t] = U[t] + q*U[i] */
{
mpz_mul (tmp1, q, U[ui_i][ui_j]);
/* tmp=q*uij */
mpz_add (U[ui_t][ui_j], U[ui_t][ui_j], tmp1);
/* utj = utj + q*uij */
}
}
/* s = min (s, zdot (U[t], U[t]) */
vz_dot (tmp1, U[ui_t], U[ui_t], ui_t +
1 );
if (mpz_cmp (tmp1, s) <
0 )
mpz_set (s, tmp1);
ui_k = ui_t;
ui_j =
0 ;
/* WARNING: ui_j no longer a temp. */
/* S5 [Transform.] */
if (g_debug > DEBUG_2)
printf (
"(t, k, j, q1, q2, ...)\n" );
do
{
if (g_debug > DEBUG_2)
printf (
"(%u, %u, %u" , ui_t +
1 , ui_k +
1 , ui_j +
1 );
for (ui_i =
0 ; ui_i <= ui_t; ui_i++)
{
if (ui_i != ui_j)
{
vz_dot (tmp1, V[ui_i], V[ui_j], ui_t +
1 );
/* tmp1=dot(Vi,Vj). */
mpz_abs (tmp2, tmp1);
mpz_mul_ui (tmp2, tmp2,
2 );
/* tmp2 = 2*abs(dot(Vi,Vj) */
vz_dot (tmp3, V[ui_j], V[ui_j], ui_t +
1 );
/* tmp3=dot(Vj,Vj). */
if (mpz_cmp (tmp2, tmp3) >
0 )
{
zdiv_round (q, tmp1, tmp3);
/* q=round(Vi.Vj/Vj.Vj) */
if (g_debug > DEBUG_2)
{
printf (
", " );
mpz_out_str (stdout,
10 , q);
}
for (ui_l =
0 ; ui_l <= ui_t; ui_l++)
{
mpz_mul (tmp1, q, V[ui_j][ui_l]);
mpz_sub (V[ui_i][ui_l], V[ui_i][ui_l], tmp1);
/* Vi=Vi-q*Vj */
mpz_mul (tmp1, q, U[ui_i][ui_l]);
mpz_add (U[ui_j][ui_l], U[ui_j][ui_l], tmp1);
/* Uj=Uj+q*Ui */
}
vz_dot (tmp1, U[ui_j], U[ui_j], ui_t +
1 );
/* tmp1=dot(Uj,Uj) */
if (mpz_cmp (tmp1, s) <
0 )
/* s = min(s,dot(Uj,Uj)) */
mpz_set (s, tmp1);
ui_k = ui_j;
}
else if (g_debug > DEBUG_2)
printf (
", #" );
/* 2|Vi.Vj| <= Vj.Vj */
}
else if (g_debug > DEBUG_2)
printf (
", *" );
/* i == j */
}
if (g_debug > DEBUG_2)
printf (
")\n" );
/* S6 [Advance j.] */
if (ui_j == ui_t)
ui_j =
0 ;
else
ui_j++;
}
while (ui_j != ui_k);
/* S5 */
/* From Knuth p. 104: "The exhaustive search in steps S8-S10
reduces the value of s only rarely." */
#ifdef DO_SEARCH
/* S7 [Prepare for search.] */
/* Find minimum in (x[1], ..., x[t]) satisfying condition
x[k]^2 <= f(y[1], ...,y[t]) * dot(V[k],V[k]) */
ui_k = ui_t;
if (g_debug > DEBUG_2)
{
printf (
"searching..." );
/*for (f = 0; f < ui_t*/
fflush (stdout);
}
/* Z[i] = floor (sqrt (floor (dot(V[i],V[i]) * s / m^2))); */
mpz_pow_ui (tmp1, m,
2 );
mpf_set_z (f_tmp1, tmp1);
mpf_set_z (f_tmp2, s);
mpf_div (f_tmp1, f_tmp2, f_tmp1);
/* f_tmp1 = s/m^2 */
for (ui_i =
0 ; ui_i <= ui_t; ui_i++)
{
vz_dot (tmp1, V[ui_i], V[ui_i], ui_t +
1 );
mpf_set_z (f_tmp2, tmp1);
mpf_mul (f_tmp2, f_tmp2, f_tmp1);
f_floor (f_tmp2, f_tmp2);
mpf_sqrt (f_tmp2, f_tmp2);
mpz_set_f (Z[ui_i], f_tmp2);
}
/* S8 [Advance X[k].] */
do
{
if (g_debug > DEBUG_2)
{
printf (
"X[%u] = " , ui_k);
mpz_out_str (stdout,
10 , X[ui_k]);
printf (
"\tZ[%u] = " , ui_k);
mpz_out_str (stdout,
10 , Z[ui_k]);
printf (
"\n" );
fflush (stdout);
}
if (mpz_cmp (X[ui_k], Z[ui_k]))
{
mpz_add_ui (X[ui_k], X[ui_k],
1 );
for (ui_i =
0 ; ui_i <= ui_t; ui_i++)
mpz_add (Y[ui_i], Y[ui_i], U[ui_k][ui_i]);
/* S9 [Advance k.] */
while (++ui_k <= ui_t)
{
mpz_neg (X[ui_k], Z[ui_k]);
mpz_mul_ui (tmp1, Z[ui_k],
2 );
for (ui_i =
0 ; ui_i <= ui_t; ui_i++)
{
mpz_mul (tmp2, tmp1, U[ui_k][ui_i]);
mpz_sub (Y[ui_i], Y[ui_i], tmp2);
}
}
vz_dot (tmp1, Y, Y, ui_t +
1 );
if (mpz_cmp (tmp1, s) <
0 )
mpz_set (s, tmp1);
}
}
while (--ui_k);
#endif /* DO_SEARCH */
mpf_set_z (f_tmp1, s);
mpf_sqrt (rop[ui_t -
1 ], f_tmp1);
#ifdef DO_SEARCH
if (g_debug > DEBUG_2)
printf (
"done.\n" );
#endif /* DO_SEARCH */
}
/* S4 loop */
/* Clear GMP variables. */
mpf_clear (f_tmp1);
mpf_clear (f_tmp2);
for (ui_i =
0 ; ui_i < GMP_SPECT_MAXT; ui_i++)
{
for (ui_j =
0 ; ui_j < GMP_SPECT_MAXT; ui_j++)
{
mpz_clear (U[ui_i][ui_j]);
mpz_clear (V[ui_i][ui_j]);
}
mpz_clear (X[ui_i]);
mpz_clear (Y[ui_i]);
mpz_clear (Z[ui_i]);
}
mpz_clear (tmp1);
mpz_clear (tmp2);
mpz_clear (tmp3);
mpz_clear (h);
mpz_clear (hp);
mpz_clear (r);
mpz_clear (s);
mpz_clear (p);
mpz_clear (pp);
mpz_clear (q);
mpz_clear (u);
mpz_clear (v);
return ;
}
Messung V0.5 in Prozent C=93 H=96 G=94
¤ Dauer der Verarbeitung: 0.12 Sekunden
¤
*© Formatika GbR, Deutschland