/* Copyright (C) 2019 Alessandro Languasco */ #define _GNU_SOURCE #include #include #include #include #include #include #define REAL 0 #define IMAG 1 void prntc(fftwl_complex* result, ptrdiff_t dim) { /* for checking results */ int i; for (i = 0; i < dim; ++i) { printf("%Lf\n", result[i][REAL]); printf("%Lf\n", result[i][IMAG]); } } void prntr(long double* result,ptrdiff_t dim) { /* for checking results */ int i; for (i = 0; i < dim; ++i) { printf("%Lf\n", result[i]); } } int main() { ptrdiff_t a; long double c; long double d; ptrdiff_t i; ptrdiff_t j; ptrdiff_t k; ptrdiff_t m; ptrdiff_t q; ptrdiff_t primroot; ptrdiff_t NUM_POINTS; ptrdiff_t nhalf; ptrdiff_t nquarter; long double oddresult; long double evenresult; long double pi; pi=3.1415926535897932384626433832795028841971693993751; printf("********** A. LANGUASCO *********** \n"); printf("Computation of the min_{chi neq chi_0} |L(1,chi)| with the logGamma function. \n"); printf("[LONG DOUBLE PRECISION - GURU64 - OUTPLACE transforms]\n"); printf("Acquiring q from file: q = "); FILE *myFile; myFile = fopen("primroot.res", "r"); if (myFile == NULL){ printf("File primroot.res doesn't exist\n"); exit (0); } fscanf(myFile, "%tu", &q); printf("%td\n",q); /*getting the value of the primitive root g mod q used in the precomputation */ fscanf(myFile, "%tu", &primroot); fclose(myFile); NUM_POINTS=q-1; nhalf=NUM_POINTS/2; nquarter=nhalf/2; /*BEGIN GURU 64 PLAN PREPARATION */ printf("%s", "Start FFT plans preparation"); clock_t startplan = clock(); /* start clock */ /*********** LOGGAMMA PLAN PREPARATION ***********/ /***** for an OUTPLACE TRANSFORM *****/ long double *lngammavalues; lngammavalues = (long double*) fftwl_malloc(sizeof(long double) * nhalf); fftwl_complex *lngammatrasf; lngammatrasf = (fftwl_complex*) fftwl_malloc(sizeof(fftwl_complex) * (nquarter+1)); /***** for an INPLACE TRANSFORM *****/ /* for an INPLACE TRANSFORM; lngammavalues should be of the same dim of the output ; 2*(nquarter+1) */ /* long double *lngammavalues; lngammavalues = (long double*) fftwl_malloc(sizeof(long double) * nhalf+2); */ /* the FFT of a real sequence with length = nhalf has nquarter + 1 complex positions = nhalf+2 long double positions */ /* fftwl_complex *lngammatrasf; */ /* lngammatrasf = (fftwl_complex*)lngammavalues; */ int rank=1; fftw_iodim64 *dims=malloc(rank*sizeof(fftw_iodim64)); dims[0].n= nhalf; /* length of the trasform */ dims[0].is=1; dims[0].os=1; int howmany_rank=1; fftw_iodim64 *howmany_dims=malloc(howmany_rank*sizeof(fftw_iodim64)); howmany_dims[0].n=1; howmany_dims[0].is=1; howmany_dims[0].os=1; fftwl_plan plan_lngamma = fftwl_plan_guru64_dft_r2c(rank, /*rank=1 means monodimensional vector*/ dims, /* NUM_POINTS */ howmany_rank, howmany_dims, lngammavalues, /*input*/ lngammatrasf, /*output; for outplace transforms*/ FFTW_ESTIMATE); /*flags*/ if (plan_lngamma ==NULL){fprintf(stderr,"loggamma plan creation failed\n");exit(1);} /********** ak PLAN PREPARATION ***********/ /***** for an OUTPLACE TRANSFORM *****/ fftwl_complex *akvalues; akvalues = (fftwl_complex*) fftwl_malloc(sizeof(fftwl_complex) * nhalf); fftwl_complex *akvalues_trasf; /* the FFT of a complex sequence with length = nhalf has nhalf complex positions*/ akvalues_trasf = (fftwl_complex*) fftwl_malloc(sizeof(fftwl_complex) * nhalf); /***** for an INPLACE TRANSFORM *****/ /* This is a FORWARD transform; corresponds to the sum over a of conj(chi)(a) */ /*fftwl_complex *akvalues; akvalues = (fftwl_complex*) fftwl_malloc(sizeof(fftwl_complex) * nhalf); */ /*fftwl_complex *akvalues_trasf;*/ /* the FFT of a complex sequence with length = nhalf has nhalf complex positions*/ /* akvalues_trasf = (fftwl_complex*) fftwl_malloc(sizeof(fftwl_complex) * nhalf);*/ fftw_iodim64 *ak_dims=malloc(rank*sizeof(fftw_iodim64)); ak_dims[0].n= nhalf; /* length of the trasform */ ak_dims[0].is=1; ak_dims[0].os=1; fftwl_plan plan_ak = fftwl_plan_guru64_dft(rank, /*rank=1 means monodimensional vector*/ ak_dims, /* nhalf */ howmany_rank, howmany_dims, akvalues, /*input for outplace transforms*/ akvalues_trasf, /*output; for outplace transforms*/ FFTW_FORWARD, /* -1 because it is the sign of FORWARD transform */ FFTW_ESTIMATE); /*flags*/ if (plan_ak ==NULL){fprintf(stderr,"ak plan creation failed\n");exit(1);} clock_t endplan = clock(); /* stop clock */ /*END GURU 64 PLAN PREPARATION */ /*********** acquire the values to generate sequence g^k%q ***********/ printf("%s", "Generating log(gamma(a/q)) and g^k%q [decimated in frequency]"); /******** initialisation for log gamma and a_k **********/ /* COMMENT: the speediness of the DIF for a_k can be improved by replacing the nhalf calls to sin and cos with the summation formulae for the sin and cos functions (so using just one call of sin and cos and about nhalf sums and products). This works nicely in quadruple precision but in the long double precision it introduces some computation errors in the final value of the euler-kronecker constants. So we are using here the slower but more precise version of the DIF for the a_k sequence. */ clock_t startinitseq = clock(); /* start clock */ long double sinvalue; long double cosvalue; long double logpi = logl(pi); long double twist = 0.0L; long double angle = (long double) pi/nhalf; a = 1; for (k = 0; k