/* Copyright (C) 2020 Alessandro Languasco */ #define _GNU_SOURCE #include #include #include #include #include #include #include #define REAL 0 #define IMAG 1 char bufRe[512]; char bufIm[512]; char bufPrint[512]; void printFloat128(__float128 x) { size_t n = quadmath_snprintf(bufPrint, sizeof(bufPrint), "%+-#*.20Qf", 92, x); if (n < sizeof(bufPrint)) printf("%s\n", bufPrint); else printf("--error--: n = %ld\n", n); } void getSvalues(__float128* Svalues, unsigned long long int 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); /* serve a 'consumare' il newline dopo l'intero dummy */ fgets(bufRe, sizeof(bufRe), myFile); for (i = 0; i < dim; i++){ fgets(bufRe, sizeof(bufRe), myFile); Svalues[i] = strtoflt128 (bufRe, NULL); /* printFloat128(Svalues[i]); */ } /* printf("\ngetSValues() done.\n");*/ /*for (i = 0; i < q-1; i++){ printf("%Qg\n", Svalues[i]); }*/ fclose(myFile); } void prntc(fftwq_complex* result, unsigned long long int NUM_POINTS) { /* for checking results */ int i; int n; int width = 46; for (i = 0; i < NUM_POINTS; ++i) { /* printf("%llu\n", result[i][REAL]); */ n = quadmath_snprintf(bufRe, sizeof(bufRe), "%+-#*.20Qf", width, result[i][REAL]); if ((size_t) n < sizeof bufRe) printf ("%s\n", bufRe); /* printf("%Qg\n", result[i][IMAG]); */ n = quadmath_snprintf(bufIm, sizeof(bufIm), "%+-#*.20Qf", width, result[i][IMAG]); if ((size_t) n < sizeof bufIm) printf ("%s\n", bufIm); } } void prntr(__float128* result,unsigned long long int NUM_POINTS) { /* for checking results */ int i; int n; int width = 46; for (i = 0; i < NUM_POINTS; ++i) { n = quadmath_snprintf(bufRe, sizeof(bufRe), "%+-#*.20Qf", width, result[i]); if ((size_t) n < sizeof bufRe) printf ("%s\n", bufRe); } } int main() { ptrdiff_t a; __float128 c; __float128 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; __float128 oddresult; __float128 evenresult; __float128 res; __float128 Eulergamma; __float128 pi; Eulergamma=0.57721566490153286060651209008240243104; pi=M_PIq; printf("********** A. LANGUASCO *********** \n"); printf("Computation of the min_{chi neq chi_0} |L'/L(1,chi)| with the S function. [Quadruple 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 ***********/ /* __float128 *lngammavalues; lngammavalues = (__float128*) fftwq_malloc(sizeof(__float128) * NUM_POINTS); fftwq_complex *lngammatrasf; lngammatrasf = (fftwq_complex*) fftwq_malloc(sizeof(fftwq_complex) * (nhalf+1));*/ /***** for an INPLACE TRANSFORM *****/ __float128 *lngammavalues; lngammavalues = (__float128*) fftwq_malloc(sizeof(__float128) * 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 __float128 positions*/ fftwq_complex *lngammatrasf; lngammatrasf = (fftwq_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; fftwq_plan plan_lngamma = fftwq_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 *****/ /*fftwq_complex *akvalues; akvalues = (fftwq_complex*) fftwq_malloc(sizeof(fftwq_complex) * nhalf); */ fftwq_complex *akvalues_trasf; /* the FFT of a complex sequence with length = nhalf has nhalf complex positions*/ akvalues_trasf = (fftwq_complex*) fftwq_malloc(sizeof(fftwq_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; fftwq_plan plan_ak = fftwq_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 *****/ /*__float128 *Svalues; Svalues = (__float128*) fftwq_malloc(sizeof(__float128) * nhalf); fftwq_complex *Strasf; Strasf = (fftwq_complex*) fftwq_malloc(sizeof(fftwq_complex) * (nquarter+1));*/ __float128 *Svalues; Svalues = (__float128*) fftwq_malloc(sizeof(__float128) * 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 __float128 positions*/ fftwq_complex *Strasf; Strasf = (fftwq_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; fftwq_plan plan_S = fftwq_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 */ __float128 sinvalue; __float128 cosvalue; __float128 logpi = logq(pi); __float128 twist = 0.0q; __float128 angle = (__float128) pi/nhalf; a = 1; for (k = 0; k