/* teta -- test file for the Dedekind eta function.
Copyright (C) 2022 INRIA
This file is part of GNU MPC.
GNU MPC is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
GNU MPC 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 Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see http://www.gnu.org/licenses/ .
*/
#include <math.h>
#include "mpc-tests.h"
static void
mpcb_j_err (mpcb_ptr j, mpc_srcptr z, unsigned long int err_re,
unsigned long int err_im)
/* Compute the j-function in z; err_re and err_im have the same meaning
as in mpcb_eta_err. */
{
const mpfr_prec_t p = mpc_get_prec (z);
mpc_t z2;
mpcb_t eta, eta2, sixteen;
mpc_init2 (z2, p);
mpcb_init (eta);
mpcb_init (eta2);
mpcb_init (sixteen);
/* Compute f1 (z) = eta (z/2) / eta (z). */
mpcb_eta_err (eta, z, err_re, err_im);
mpc_div_2ui (z2, z, 1, MPC_RNDNN);
mpcb_eta_err (eta2, z2, err_re, err_im);
mpcb_div (eta, eta2, eta);
/* Compute gamma2 = (f1^24 + 16) / f1^8. */
mpcb_set_ui_ui (sixteen, 16, 0, p);
mpcb_pow_ui (eta, eta, 8);
mpcb_pow_ui (eta2, eta, 3);
mpcb_add (eta2, eta2, sixteen);
mpcb_div (eta2, eta2, eta);
/* Compute j = gamma2^3. */
mpcb_pow_ui (j, eta2, 3);
mpc_clear (z2);
mpcb_clear (eta);
mpcb_clear (eta2);
mpcb_clear (sixteen);
}
static int
test_eta (void)
{
const mpfr_prec_t p = 300;
mpc_t z, eta;
mpcb_t j;
mpfr_t fuzz;
mpz_t re_z, tmp;
long int re, im;
int ok;
mpc_init2 (z, p);
mpc_init2 (eta, p);
mpcb_init (j);
mpfr_init2 (fuzz, 2*p);
mpfr_set_si (mpc_realref (z), -1, MPFR_RNDN);
mpfr_set_ui (mpc_imagref (z), 163, MPFR_RNDD);
mpfr_sqrt (mpc_imagref (z), mpc_imagref (z), MPFR_RNDD);
mpc_div_2ui (z, z, 1, MPC_RNDNN);
/* Check whether mpc_eta_fund avoids an infinite loop. */
mpc_eta_fund (eta, z, MPC_RNDNN);
/* The error is bounded by 1/2 ulp in the real and 3 ulp in the
imaginary part, see algorithms.tex. */
mpcb_j_err (j, z, 1, 6);
/* Check whether j ((-1+sqrt(-163))/2) equals -262537412640768000.
Rounding is impossible since the result is exact, and the imaginary
part is 0; for a quick and dirty check, add the non-representable
number 0.1 + 1.1 I and use the precisions that just work. */
mpfr_set_ui (fuzz, 1, MPFR_RNDN);
mpfr_div_ui (fuzz, fuzz, 10, MPFR_RNDN);
mpfr_add (mpc_realref (j->c), mpc_realref (j->c), fuzz, MPFR_RNDN);
mpfr_add (mpc_imagref (j->c), mpc_imagref (j->c), fuzz, MPFR_RNDN);
mpfr_add_ui (mpc_imagref (j->c), mpc_imagref (j->c), 1, MPFR_RNDN);
ok = mpcb_can_round (j, 291, 234, MPC_RNDNN);
mpcb_round (z, j, MPC_RNDNN);
mpz_init (re_z);
mpz_init_set_str (tmp, "-262537412640768000", 10);
mpfr_get_z (re_z, mpc_realref (z), MPFR_RNDN);
im = mpfr_get_si (mpc_imagref (z), MPFR_RNDN);
ok &= (!mpz_cmp (re_z, tmp) && im == 1);
if (!ok) {
printf ("Error for -163:\n");
MPC_OUT (z);
mpz_out_str (stdout, 10, re_z);
printf ("\n");
}
mpz_clear (tmp);
mpz_clear (re_z);
/* Check whether mpc_eta_fund (I) avoids an infinite loop. */
mpc_set_ui_ui (z, 0, 1, MPC_RNDNN);
mpc_eta_fund (eta, z, MPC_RNDNN);
/* Check whether j (I) equals 1728. */
mpcb_j_err (j, z, 0, 0);
mpfr_add (mpc_realref (j->c), mpc_realref (j->c), fuzz, MPFR_RNDN);
mpfr_add (mpc_imagref (j->c), mpc_imagref (j->c), fuzz, MPFR_RNDN);
mpfr_add_ui (mpc_imagref (j->c), mpc_imagref (j->c), 1, MPFR_RNDN);
ok &= mpcb_can_round (j, 292, 282, MPC_RNDNN);
mpcb_round (z, j, MPC_RNDNN);
re = mpfr_get_si (mpc_realref (z), MPFR_RNDN);
im = mpfr_get_si (mpc_imagref (z), MPFR_RNDN);
ok &= (re == 1728 && im == 1);
if (!ok) {
printf ("Error for -4:\n");
MPC_OUT (z);
printf ("%li\n", re);
}
mpc_clear (eta);
mpc_clear (z);
mpcb_clear (j);
mpfr_clear (fuzz);
return !ok;
}
int
main (void)
{
return test_eta ();
}