/*
   This file is part of Numerix.  Numerix 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 2 of the License, or (at your option) any later version.

   This program 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 this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA 
*/

/* +------------------------------------------------------------------------+
   |                                                                        |
   |                            Mesures de vitesse                          |
   |                                                                        |
   +------------------------------------------------------------------------+ */

/* M. Quercia, le 31/01/2001 */

#include <stdlib.h>
#include <stdio.h>
#include <sys/times.h>
#include <time.h>
#include <gmp.h>

                            /* +-----------------+
                               |  Chronométrage  |
                               +-----------------+ */

void chrono(char *msg) {
  static double tlast = 0;
  double t;
  struct tms buf;

  times(&buf);
  t = (double)(buf.tms_utime + buf.tms_stime)/CLK_TCK;
  fprintf(stderr,"%8.2f %8.2f %s\n",t,t-tlast,msg);
  fflush(stderr);
  tlast = t;
}

                    /* +-----------------------+
                       |  Programme principal  |
                       +-----------------------+ */


int main(int argc, char **argv) {
  long bits=100;
  int  all=0, mul=0, sqr=0, quomod=0, quo=0, sqrt=0, gcd=0, gcd_ex=0, help=0;
  int  nrep=1,i;
  char *cmd = argv[0];
  mpz_t a,b,c,t,u,v;

  argv++;
  while (*argv) {
    if      (strcmp(*argv,"-h")      == 0)   help   = 1;
    else if (strcmp(*argv,"-r")      == 0)   {argv++; if (argv) nrep=strtol(argv[0],NULL,0); else help=1;}
    else if (strcmp(*argv,"-mul")    == 0)   mul    = 1;
    else if (strcmp(*argv,"-sqr")    == 0)   sqr    = 1;
    else if (strcmp(*argv,"-quomod") == 0)   quomod = 1;
    else if (strcmp(*argv,"-quo")    == 0)   quo    = 1;
    else if (strcmp(*argv,"-sqrt")   == 0)   sqrt   = 1;
    else if (strcmp(*argv,"-gcd")    == 0)   gcd    = 1;
    else if (strcmp(*argv,"-gcd_ex") == 0)   gcd_ex = 1;
    else if (strcmp(*argv,"-all")    == 0)   all    = 1;
    else if (strcmp(*argv,"-test")   == 0)   {all=1; bits=10000;}
    else bits = strtol(argv[0],NULL,0);
    argv++;
  }

  if (help) printf("usage: %s [bits] [-r nrep] [-mul] [-sqr] [-quomod] [-quo] [-sqrt] [-gcd] [-gcd_ex] [-all]\n",cmd);
  else {

    mpz_init(a);
    mpz_init(b);
    mpz_init(c);
    mpz_init(t);
    mpz_init(u);
    mpz_init(v);

    mpz_random(a,  bits/mp_bits_per_limb); mpz_setbit(a,  bits);
    mpz_random(b,  bits/mp_bits_per_limb); mpz_setbit(b,  bits);
    mpz_random(c,2*bits/mp_bits_per_limb); mpz_setbit(c,2*bits);

    chrono("début");
    if ((all) || (mul))    {for (i=0; i<nrep; i++) mpz_mul(t,a,b);         chrono("mul");}
    if ((all) || (sqr))    {for (i=0; i<nrep; i++) mpz_mul(t,a,a);         chrono("sqr");}
    if ((all) || (quomod)) {for (i=0; i<nrep; i++) mpz_fdiv_qr(t,u,c,b);   chrono("quomod");}
    if ((all) || (quo))    {for (i=0; i<nrep; i++) mpz_fdiv_q (t,c,b);     chrono("quo");}
    if ((all) || (sqrt))   {for (i=0; i<nrep; i++) mpz_sqrt   (t,c);       chrono("sqrt");}
    if ((all) || (gcd))    {for (i=0; i<nrep; i++) mpz_gcd    (t,a,b);     chrono("gcd");}
    if ((all) || (gcd_ex)) {for (i=0; i<nrep; i++) mpz_gcdext (t,u,v,a,b); chrono("gcd_ex");}

    mpz_clear(a);
    mpz_clear(b);
    mpz_clear(c);
    mpz_clear(t);
    mpz_clear(u);
    mpz_clear(v);

  }
  fflush(stdout); fflush(stderr);
  return(0);
}
