/* Copyright (C) 2020 Alessandro Languasco */ #define _GNU_SOURCE #include #include #include #include #include #include #define REAL 0 #define IMAG 1 void getSvalues(long double* Svalues, ptrdiff_t dim) { FILE *myFile; myFile = fopen("precomp_S-DIF.res", "r"); int i; int dummy; if (myFile == NULL){ printf("File precomp_S-DIF.res doesn't exist\n"); exit (0); } fscanf(myFile, "%d", &dummy); for (i = 0; i < dim; i++){ fscanf(myFile, "%Lf", &Svalues[i]); } fclose(myFile); } 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 qcheck; ptrdiff_t primroot; ptrdiff_t NUM_POINTS; ptrdiff_t nhalf; ptrdiff_t nquarter; long double oddresult; long double evenresult; long double res; long double Eulergamma; long double pi; Eulergamma=0.57721566490153286060651209008240243104; pi=3.1415926535897932384626433832795028841971693993751; printf("********** A. LANGUASCO *********** \n"); printf("Computation of the min_{chi neq chi_0} |L'/L(1,chi)| with the S function. [LONG DOUBLE PRECISION - GURU64]\n"); printf("Acquiring q from file: q = "); FILE *myFile; myFile = fopen("precomp_S-DIF.res", "r"); if (myFile == NULL){ printf("File precomp_S-DIF.res doesn't exist\n"); exit (0); } fscanf(myFile, "%tu", &q); printf("%td\n",q); 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 ***********/ /* long double *lngammavalues; lngammavalues = (long double*) fftwl_malloc(sizeof(long double) * NUM_POINTS); fftwl_complex *lngammatrasf; lngammatrasf = (fftwl_complex*) fftwl_malloc(sizeof(fftwl_complex) * (nhalf+1));*/ /***** for an INPLACE TRANSFORM *****/ long double *lngammavalues; lngammavalues = (long double*) fftwl_malloc(sizeof(long double) * NUM_POINTS+2); /* for an INPLACE TRANSFORM; lngammavalues should be of the same dim of the output ; 2*(nhalf+1) */ /* the FFT of a real sequence with length = NUM_POINTS has nhalf + 1 complex positions = NUM_POINTS+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= NUM_POINTS; /* 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 IN PLACE*/ FFTW_ESTIMATE); /*flags*/ if (plan_lngamma ==NULL){fprintf(stderr,"loggamma plan creation failed\n");exit(1);} /********** ak PLAN PREPARATION ***********/ /***** for an INPLACE 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); 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_trasf, /*input for INPLACE transforms*/ akvalues_trasf, /*output; for INPLACE 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);} /*********** S PLAN PREPARATION ***********/ /***** for an INPLACE TRANSFORM *****/ /*long double *Svalues; Svalues = (long double*) fftwl_malloc(sizeof(long double) * nhalf); fftwl_complex *Strasf; Strasf = (fftwl_complex*) fftwl_malloc(sizeof(fftwl_complex) * (nquarter+1));*/ long double *Svalues; Svalues = (long double*) fftwl_malloc(sizeof(long double) * nhalf+2); /* for an INPLACE TRANSFORM; Svalues should be of the same dim of the output ; 2*(nquarter+1) */ /* the FFT of a real sequence with length = nhalf has nquarter + 1 complex positions = nhalf+2 long double positions*/ fftwl_complex *Strasf; Strasf = (fftwl_complex*)Svalues; /* for an INPLACE TRANSFORM */ fftw_iodim64 *S_dims=malloc(rank*sizeof(fftw_iodim64)); S_dims[0].n= nhalf; /* length of the trasform */ S_dims[0].is=1; S_dims[0].os=1; fftwl_plan plan_S = fftwl_plan_guru64_dft_r2c(rank, /*rank=1 means monodimensional vector*/ S_dims, /* nhalf */ howmany_rank, howmany_dims, Svalues, /*input*/ Strasf, /*output*/ FFTW_ESTIMATE); /*flags*/ if (plan_S ==NULL){fprintf(stderr,"S plan creation failed\n");exit(1);} clock_t endplan = clock(); /* stop clock */ printf("%s\n", ". Done"); /*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]"); myFile = fopen("primroot.res", "r"); if (myFile == NULL){ printf("\n ****** ERROR: File primroot.res doesn't exist\n"); exit (0); } /*checking if it is the correct q */ fscanf(myFile, "%tu", &qcheck); if (qcheck != q) {printf("\n%s", "******* ERROR: These is the generator for q = "); printf("%td\n",qcheck); exit (0); }; /*getting the value of the primitive root g mod q used in the precomputation */ fscanf(myFile, "%tu", &primroot); /*printf("%lu",primroot);*/ /******** 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 unfortunately introduces some computation errors in the final value. 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