github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tests/rand/findlc.c (about)

     1  /*
     2  Copyright 2000 Free Software Foundation, Inc.
     3  
     4  This file is part of the GNU MP Library test suite.
     5  
     6  The GNU MP Library test suite is free software; you can redistribute it
     7  and/or modify it under the terms of the GNU General Public License as
     8  published by the Free Software Foundation; either version 3 of the License,
     9  or (at your option) any later version.
    10  
    11  The GNU MP Library test suite is distributed in the hope that it will be
    12  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    14  Public License for more details.
    15  
    16  You should have received a copy of the GNU General Public License along with
    17  the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
    18  
    19  #include <stdio.h>
    20  #include <stdlib.h>
    21  #include <unistd.h>
    22  #include <signal.h>
    23  #include <math.h>
    24  #include "gmp.h"
    25  #include "gmpstat.h"
    26  
    27  #define RCSID(msg) \
    28  static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
    29  
    30  RCSID("$Id$");
    31  
    32  int g_debug = 0;
    33  
    34  static mpz_t a;
    35  
    36  static void
    37  sh_status (int sig)
    38  {
    39    printf ("sh_status: signal %d caught. dumping status.\n", sig);
    40  
    41    printf ("  a = ");
    42    mpz_out_str (stdout, 10, a);
    43    printf ("\n");
    44    fflush (stdout);
    45  
    46    if (SIGSEGV == sig)		/* remove SEGV handler */
    47      signal (SIGSEGV, SIG_DFL);
    48  }
    49  
    50  /* Input is a modulus (m).  We shall find multiplier (a) and adder (c)
    51     conforming to the rules found in the first comment block in file
    52     mpz/urandom.c.
    53  
    54     Then run a spectral test on the generator and discard any
    55     multipliers not passing.  */
    56  
    57  /* TODO:
    58  
    59     . find a better algorithm than a+=8; bigger jumps perhaps?
    60  
    61  */
    62  
    63  void
    64  mpz_true_random (mpz_t s, unsigned long int nbits)
    65  {
    66  #if __FreeBSD__
    67    FILE *fs;
    68    char c[1];
    69    int i;
    70  
    71    mpz_set_ui (s, 0);
    72    for (i = 0; i < nbits; i += 8)
    73      {
    74        for (;;)
    75  	{
    76  	  int nread;
    77  	  fs = fopen ("/dev/random", "r");
    78  	  nread = fread (c, 1, 1, fs);
    79  	  fclose (fs);
    80  	  if (nread != 0)
    81  	    break;
    82  	  sleep (1);
    83  	}
    84        mpz_mul_2exp (s, s, 8);
    85        mpz_add_ui (s, s, ((unsigned long int) c[0]) & 0xff);
    86        printf ("%d random bits\n", i + 8);
    87      }
    88    if (nbits % 8 != 0)
    89      mpz_mod_2exp (s, s, nbits);
    90  #endif
    91  }
    92  
    93  int
    94  main (int argc, char *argv[])
    95  {
    96    const char usage[] = "usage: findlc [-dv] m2exp [low_merit [high_merit]]\n";
    97    int f;
    98    int v_lose, m_lose, v_best, m_best;
    99    int c;
   100    int debug = 1;
   101    int cnt_high_merit;
   102    mpz_t m;
   103    unsigned long int m2exp;
   104  #define DIMS 6			/* dimensions run in spectral test */
   105    mpf_t v[DIMS-1];		/* spectral test result (there's no v
   106  				   for 1st dimension */
   107    mpf_t f_merit, low_merit, high_merit;
   108    mpz_t acc, minus8;
   109    mpz_t min, max;
   110    mpz_t s;
   111  
   112  
   113    mpz_init (m);
   114    mpz_init (a);
   115    for (f = 0; f < DIMS-1; f++)
   116      mpf_init (v[f]);
   117    mpf_init (f_merit);
   118    mpf_init_set_d (low_merit, .1);
   119    mpf_init_set_d (high_merit, .1);
   120  
   121    while ((c = getopt (argc, argv, "a:di:hv")) != -1)
   122      switch (c)
   123        {
   124        case 'd':			/* debug */
   125  	g_debug++;
   126  	break;
   127  
   128        case 'v':			/* print version */
   129  	puts (rcsid[1]);
   130  	exit (0);
   131  
   132        case 'h':
   133        case '?':
   134        default:
   135  	fputs (usage, stderr);
   136  	exit (1);
   137        }
   138  
   139    argc -= optind;
   140    argv += optind;
   141  
   142    if (argc < 1)
   143      {
   144        fputs (usage, stderr);
   145        exit (1);
   146      }
   147  
   148    /* Install signal handler. */
   149    if (SIG_ERR == signal (SIGSEGV, sh_status))
   150      {
   151        perror ("signal (SIGSEGV)");
   152        exit (1);
   153      }
   154    if (SIG_ERR == signal (SIGHUP, sh_status))
   155      {
   156        perror ("signal (SIGHUP)");
   157        exit (1);
   158      }
   159  
   160    printf ("findlc: version: %s\n", rcsid[1]);
   161    m2exp = atol (argv[0]);
   162    mpz_init_set_ui (m, 1);
   163    mpz_mul_2exp (m, m, m2exp);
   164    printf ("m = 0x");
   165    mpz_out_str (stdout, 16, m);
   166    puts ("");
   167  
   168    if (argc > 1)			/* have low_merit */
   169      mpf_set_str (low_merit, argv[1], 0);
   170    if (argc > 2)			/* have high_merit */
   171      mpf_set_str (high_merit, argv[2], 0);
   172  
   173    if (debug)
   174      {
   175        fprintf (stderr, "low_merit = ");
   176        mpf_out_str (stderr, 10, 2, low_merit);
   177        fprintf (stderr, "; high_merit = ");
   178        mpf_out_str (stderr, 10, 2, high_merit);
   179        fputs ("\n", stderr);
   180      }
   181  
   182    mpz_init (minus8);
   183    mpz_set_si (minus8, -8L);
   184    mpz_init_set_ui (acc, 0);
   185    mpz_init (s);
   186    mpz_init_set_d (min, 0.01 * pow (2.0, (double) m2exp));
   187    mpz_init_set_d (max, 0.99 * pow (2.0, (double) m2exp));
   188  
   189    mpz_true_random (s, m2exp);	/* Start.  */
   190    mpz_setbit (s, 0);		/* Make it odd.  */
   191  
   192    v_best = m_best = 2*(DIMS-1);
   193    for (;;)
   194      {
   195        mpz_add (acc, acc, s);
   196        mpz_mod_2exp (acc, acc, m2exp);
   197  #if later
   198        mpz_and_si (a, acc, -8L);
   199  #else
   200        mpz_and (a, acc, minus8);
   201  #endif
   202        mpz_add_ui (a, a, 5);
   203        if (mpz_cmp (a, min) <= 0 || mpz_cmp (a, max) >= 0)
   204  	continue;
   205  
   206        spectral_test (v, DIMS, a, m);
   207        for (f = 0, v_lose = m_lose = 0, cnt_high_merit = DIMS-1;
   208  	   f < DIMS-1; f++)
   209  	{
   210  	  merit (f_merit, f + 2, v[f], m);
   211  
   212  	  if (mpf_cmp_ui (v[f], 1 << (30 / (f + 2) + (f == 2))) < 0)
   213  	    v_lose++;
   214  
   215  	  if (mpf_cmp (f_merit, low_merit) < 0)
   216  	    m_lose++;
   217  
   218  	  if (mpf_cmp (f_merit, high_merit) >= 0)
   219  	    cnt_high_merit--;
   220  	}
   221  
   222        if (0 == v_lose && 0 == m_lose)
   223  	{
   224  	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
   225  	  if (0 == cnt_high_merit)
   226  	    break;		/* leave loop */
   227  	}
   228        if (v_lose < v_best)
   229  	{
   230  	  v_best = v_lose;
   231  	  printf ("best (v_lose=%d; m_lose=%d): ", v_lose, m_lose);
   232  	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
   233  	}
   234        if (m_lose < m_best)
   235  	{
   236  	  m_best = m_lose;
   237  	  printf ("best (v_lose=%d; m_lose=%d): ", v_lose, m_lose);
   238  	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
   239  	}
   240      }
   241  
   242    mpz_clear (m);
   243    mpz_clear (a);
   244    for (f = 0; f < DIMS-1; f++)
   245      mpf_clear (v[f]);
   246    mpf_clear (f_merit);
   247    mpf_clear (low_merit);
   248    mpf_clear (high_merit);
   249  
   250    printf ("done.\n");
   251    return 0;
   252  }