Blame demos/qcn.c

Packit 5c3484
/* Use mpz_kronecker_ui() to calculate an estimate for the quadratic
Packit 5c3484
   class number h(d), for a given negative fundamental discriminant, using
Packit 5c3484
   Dirichlet's analytic formula.
Packit 5c3484
Packit 5c3484
Copyright 1999-2002 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
This program is free software; you can redistribute it and/or modify it
Packit 5c3484
under the terms of the GNU General Public License as published by the Free
Packit 5c3484
Software Foundation; either version 3 of the License, or (at your option)
Packit 5c3484
any later version.
Packit 5c3484
Packit 5c3484
This program is distributed in the hope that it will be useful, but WITHOUT
Packit 5c3484
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit 5c3484
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
Packit 5c3484
more details.
Packit 5c3484
Packit 5c3484
You should have received a copy of the GNU General Public License along with
Packit 5c3484
this program.  If not, see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Usage: qcn [-p limit] <discriminant>...
Packit 5c3484
Packit 5c3484
   A fundamental discriminant means one of the form D or 4*D with D
Packit 5c3484
   square-free.  Each argument is checked to see it's congruent to 0 or 1
Packit 5c3484
   mod 4 (as all discriminants must be), and that it's negative, but there's
Packit 5c3484
   no check on D being square-free.
Packit 5c3484
Packit 5c3484
   This program is a bit of a toy, there are better methods for calculating
Packit 5c3484
   the class number and class group structure.
Packit 5c3484
Packit 5c3484
   Reference:
Packit 5c3484
Packit 5c3484
   Daniel Shanks, "Class Number, A Theory of Factorization, and Genera",
Packit 5c3484
   Proc. Symp. Pure Math., vol 20, 1970, pages 415-440.
Packit 5c3484
Packit 5c3484
*/
Packit 5c3484
Packit 5c3484
#include <math.h>
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include <stdlib.h>
Packit 5c3484
#include <string.h>
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
Packit 5c3484
#ifndef M_PI
Packit 5c3484
#define M_PI  3.14159265358979323846
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* A simple but slow primality test.  */
Packit 5c3484
int
Packit 5c3484
prime_p (unsigned long n)
Packit 5c3484
{
Packit 5c3484
  unsigned long  i, limit;
Packit 5c3484
Packit 5c3484
  if (n == 2)
Packit 5c3484
    return 1;
Packit 5c3484
  if (n < 2 || !(n&1))
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  limit = (unsigned long) floor (sqrt ((double) n));
Packit 5c3484
  for (i = 3; i <= limit; i+=2)
Packit 5c3484
    if ((n % i) == 0)
Packit 5c3484
      return 0;
Packit 5c3484
Packit 5c3484
  return 1;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* The formula is as follows, with d < 0.
Packit 5c3484
Packit 5c3484
	       w * sqrt(-d)      inf      p
Packit 5c3484
	h(d) = ------------ *  product --------
Packit 5c3484
		  2 * pi         p=2   p - (d/p)
Packit 5c3484
Packit 5c3484
Packit 5c3484
   (d/p) is the Kronecker symbol and the product is over primes p.  w is 6
Packit 5c3484
   when d=-3, 4 when d=-4, or 2 otherwise.
Packit 5c3484
Packit 5c3484
   Calculating the product up to p=infinity would take a long time, so for
Packit 5c3484
   the estimate primes up to 132,000 are used.  Shanks found this giving an
Packit 5c3484
   accuracy of about 1 part in 1000, in normal cases.  */
Packit 5c3484
Packit 5c3484
unsigned long  p_limit = 132000;
Packit 5c3484
Packit 5c3484
double
Packit 5c3484
qcn_estimate (mpz_t d)
Packit 5c3484
{
Packit 5c3484
  double  h;
Packit 5c3484
  unsigned long  p;
Packit 5c3484
Packit 5c3484
  /* p=2 */
Packit 5c3484
  h = sqrt (-mpz_get_d (d)) / M_PI
Packit 5c3484
    * 2.0 / (2.0 - mpz_kronecker_ui (d, 2));
Packit 5c3484
Packit 5c3484
  if (mpz_cmp_si (d, -3) == 0)       h *= 3;
Packit 5c3484
  else if (mpz_cmp_si (d, -4) == 0)  h *= 2;
Packit 5c3484
Packit 5c3484
  for (p = 3; p <= p_limit; p += 2)
Packit 5c3484
    if (prime_p (p))
Packit 5c3484
      h *= (double) p / (double) (p - mpz_kronecker_ui (d, p));
Packit 5c3484
Packit 5c3484
  return h;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
qcn_str (char *num)
Packit 5c3484
{
Packit 5c3484
  mpz_t  z;
Packit 5c3484
Packit 5c3484
  mpz_init_set_str (z, num, 0);
Packit 5c3484
Packit 5c3484
  if (mpz_sgn (z) >= 0)
Packit 5c3484
    {
Packit 5c3484
      mpz_out_str (stdout, 0, z);
Packit 5c3484
      printf (" is not supported (negatives only)\n");
Packit 5c3484
    }
Packit 5c3484
  else if (mpz_fdiv_ui (z, 4) != 0 && mpz_fdiv_ui (z, 4) != 1)
Packit 5c3484
    {
Packit 5c3484
      mpz_out_str (stdout, 0, z);
Packit 5c3484
      printf (" is not a discriminant (must == 0 or 1 mod 4)\n");
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      printf ("h(");
Packit 5c3484
      mpz_out_str (stdout, 0, z);
Packit 5c3484
      printf (") approx %.1f\n", qcn_estimate (z));
Packit 5c3484
    }
Packit 5c3484
  mpz_clear (z);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
main (int argc, char *argv[])
Packit 5c3484
{
Packit 5c3484
  int  i;
Packit 5c3484
  int  saw_number = 0;
Packit 5c3484
Packit 5c3484
  for (i = 1; i < argc; i++)
Packit 5c3484
    {
Packit 5c3484
      if (strcmp (argv[i], "-p") == 0)
Packit 5c3484
	{
Packit 5c3484
	  i++;
Packit 5c3484
	  if (i >= argc)
Packit 5c3484
	    {
Packit 5c3484
	      fprintf (stderr, "Missing argument to -p\n");
Packit 5c3484
	      exit (1);
Packit 5c3484
	    }
Packit 5c3484
	  p_limit = atoi (argv[i]);
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  qcn_str (argv[i]);
Packit 5c3484
	  saw_number = 1;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (! saw_number)
Packit 5c3484
    {
Packit 5c3484
      /* some default output */
Packit 5c3484
      qcn_str ("-85702502803");           /* is 16259   */
Packit 5c3484
      qcn_str ("-328878692999");          /* is 1499699 */
Packit 5c3484
      qcn_str ("-928185925902146563");    /* is 52739552 */
Packit 5c3484
      qcn_str ("-84148631888752647283");  /* is 496652272 */
Packit 5c3484
      return 0;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  return 0;
Packit 5c3484
}