Fonction Zêta de Riemann en Java-Récursivité Infinie avec Forme Fonctionnelle


Note: Mise à jour le 17/06/2015. Bien sûr, cela est possible. Voir la solution ci-dessous.

, Même si quelqu'un copie et colle ce code, vous avez encore beaucoup de nettoyage à faire. Notez également que vous aurez des problèmes à l'intérieur de la bande critique de Re(s) = 0 pour Re(s) = 1 :). Mais c'est un bon début.

import java.util.Scanner;

public class NewTest{

public static void main(String[] args) {
    RiemannZetaMain func = new RiemannZetaMain();
    double s = 0;
    double start, stop, totalTime;
    Scanner scan = new Scanner(System.in);
    System.out.print("Enter the value of s inside the Riemann Zeta Function: ");
    try {
            s = scan.nextDouble();
    } 
    catch (Exception e) {
        System.out.println("You must enter a positive integer greater than 1.");
    }
    start = System.currentTimeMillis();
    if (s <= 0)
        System.out.println("Value for the Zeta Function = " + riemannFuncForm(s));
    else if (s == 1)
        System.out.println("The zeta funxtion is undefined for Re(s) = 1.");
    else if(s >= 2)
        System.out.println("Value for the Zeta Function = " + getStandardSum(s));
    else
        System.out.println("Value for the Zeta Function = " + getNewSum(s));
    stop = System.currentTimeMillis();
    totalTime = (double) (stop-start) / 1000.0;
    System.out.println("Total time taken is " + totalTime + " seconds.");
}

// Standard form the the Zeta function.
public static double standardZeta(double s) {
    int n = 1;
    double currentSum = 0;
    double relativeError = 1;
    double error = 0.000001;
    double remainder;

    while (relativeError > error) {
        currentSum = Math.pow(n, -s) + currentSum;
        remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
        relativeError =  remainder / currentSum;
        n++;
    }
    System.out.println("The number of terms summed was " + n + ".");
    return currentSum;
}

public static double getStandardSum(double s){
    return standardZeta(s);
}

//New Form
// zeta(s) = 2^(-1+2 s)/((-2+2^s) Gamma(1+s)) integral_0^infinity t^s sech^2(t) dt  for Re(s)>-1
public static double Integrate(double start, double end) {
    double currentIntegralValue = 0;
    double dx = 0.0001d; // The size of delta x in the approximation
    double x = start; // A = starting point of integration, B = ending point of integration.

    // Ending conditions for the while loop
    // Condition #1: The value of b - x(i) is less than delta(x).
    // This would throw an out of bounds exception.
    // Condition #2: The value of b - x(i) is greater than 0 (Since you start at A and split the integral 
    // up into "infinitesimally small" chunks up until you reach delta(x)*n.
    while (Math.abs(end - x) >= dx && (end - x) > 0) {
        currentIntegralValue += function(x) * dx; // Use the (Riemann) rectangle sums at xi to compute width * height
        x += dx; // Add these sums together
    }
    return currentIntegralValue;
}

private static double function(double s) {
    double sech = 1 / Math.cosh(s); // Hyperbolic cosecant
    double squared = Math.pow(sech, 2);
    return ((Math.pow(s, 0.5)) * squared);
}

public static double getNewSum(double s){
double constant = Math.pow(2, (2*s)-1) / (((Math.pow(2, s)) -2)*(gamma(1+s)));
    return constant*Integrate(0, 1000);
}

// Gamma Function - Lanczos approximation
public static double gamma(double s){
                double[] p = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
                                  771.32342877765313, -176.61502916214059, 12.507343278686905,
                                  -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
                int g = 7;
                if(s < 0.5) return Math.PI / (Math.sin(Math.PI * s)*gamma(1-s));

                s -= 1;
                double a = p[0];
                double t = s+g+0.5;
                for(int i = 1; i < p.length; i++){
                        a += p[i]/(s+i);
                }

                return Math.sqrt(2*Math.PI)*Math.pow(t, s+0.5)*Math.exp(-t)*a;
        }

//Binomial Co-efficient - NOT CURRENTLY USING
/*
public static double binomial(int n, int k)
{
    if (k>n-k)
        k=n-k;

    long b=1;
    for (int i=1, m=n; i<=k; i++, m--)
        b=b*m/i;
    return b;
} */

// Riemann's Functional Equation
// Tried this initially and utterly failed.
public static double riemannFuncForm(double s) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
double nextTerm = Math.pow(2, (1-s))*Math.pow(Math.PI, (1-s)-1)*(Math.sin((Math.PI*(1-s))/2))*gamma(1-(1-s));
double error = Math.abs(term - nextTerm);

if(s == 1.0)
    return 0;
else 
    return Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)*standardZeta(1-s);
}

}

Author: Axion004, 2015-06-12

3 answers

Ok bien nous avons compris que pour cette fonction particulière, puisque cette forme n'est pas en fait une série infinie, nous ne pouvons pas approximer en utilisant la récursivité. Cependant, la somme infinie de la série Zêta de Riemann (1\(n^s) where n = 1 to infinity) pourrait être résolue par cette méthode.

De plus, cette méthode pourrait être utilisée pour trouver toute somme, produit ou limite de série infinie.

Si vous exécutez le code que vous avez actuellement, vous obtiendrez une récursivité infinie comme 1-(1-s) = s (par exemple 1-s = t, 1-t = s donc vous allez juste basculer entre deux valeurs de s infiniment).

Ci-dessous, je parle de la somme des séries. Il semble que vous calculiez le produit de la série à la place. Les concepts ci-dessous devraient fonctionner pour l'un ou l'autre.

En plus de cela, la fonction Zêta de Riemann est une série infinie. Cela signifie qu'il n'a qu'une limite et n'atteindra jamais une somme vraie (en temps fini) et que vous ne pouvez donc pas obtenir une réponse exacte récursivité.

Cependant , si vous introduisez un facteur "seuil", vous pouvez obtenir une approximation aussi bonne que vous le souhaitez. La somme augmentera/diminuera à mesure que chaque terme sera ajouté. Une fois la somme stabilisée, vous pouvez quitter la récursivité et retourner votre somme approximative. "Stabilisé" est défini en utilisant votre facteur de seuil. Une fois que la somme varie d'un montant inférieur à ce facteur seuil (que vous avez défini), votre somme s'est stabilisée.

Un seuil plus petit conduit à un meilleure approximation, mais aussi plus long temps de calcul.

(Note: cette méthode ne fonctionne que si votre série converge, si elle a une chance de ne pas converger, vous pouvez également construire une variable maxSteps pour cesser l'exécution si la série n'a pas convergé à votre satisfaction après maxSteps étapes de récursivité.)

Voici un exemple d'implémentation, notez que vous devrez jouer avec threshold et {[6] } pour déterminer les valeurs appropriées:

/* Riemann's Functional Equation
 * threshold - if two terms differ by less than this absolute amount, return
 * currSteps/maxSteps - if currSteps becomes maxSteps, give up on convergence and return
 * currVal - the current product, used to determine threshold case (start at 1)
 */
public static double riemannFuncForm(double s, double threshold, int currSteps, int maxSteps, double currVal) {
    double nextVal = currVal*(Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)); //currVal*term
    if( s == 1.0)
        return 0;
    else if ( s == 0.0)
        return -0.5;
    else if (Math.abs(currVal-nextVal) < threshold) //When a term will change the current answer by less than threshold
        return nextVal; //Could also do currVal here (shouldn't matter much as they differ by < threshold)
    else if (currSteps == maxSteps)//When you've taken the max allowed steps
        return nextVal; //You might want to print something here so you know you didn't converge
    else //Otherwise just keep recursing
        return riemannFuncForm(1-s, threshold, ++currSteps, maxSteps, nextVal);
    }
}
 3
Author: River, 2015-06-13 23:15:05

Ce n'est pas possible.

La forme fonctionnelle de la fonction Zêta de Riemann est --

zeta(s) = 2^s pi^(-1+s) Gamma(1-s) sin((pi s)/2) zeta(1-s)

Ceci est différent de l'équation standard dans laquelle une somme infinie est mesurée de 1/k^s pour tout k = 1 à k = infini. Il est possible d'écrire cela comme quelque chose de similaire à --

// Standard form the the Zeta function.
public static double standardZeta(double s) {
    int n = 1;
    double currentSum = 0;
    double relativeError = 1;
    double error = 0.000001;
    double remainder;

    while (relativeError > error) {
        currentSum = Math.pow(n, -s) + currentSum;
        remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
        relativeError =  remainder / currentSum;
        n++;
    }
    System.out.println("The number of terms summed was " + n + ".");
    return currentSum;
}

La même logique ne s'applique pas à l'equation fonctionnelle (ce n'est pas une somme directe, c'est une relation mathématique). Cela nécessiterait une façon plutôt intelligente de concevoir un programme pour calculez les valeurs négatives de Zêta (s)!

L'interprétation littérale de ce code Java est ---

// Riemann's Functional Equation
public static double riemannFuncForm(double s) {
double currentVal = (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
if( s == 1.0)
    return 0;
else if ( s == 0.0)
    return -0.5;
else
    System.out.println("Value of next value is " + nextVal(1-s));
    return currentVal;//*nextVal(1-s);
}

public static double nextVal(double s)
{
    return (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
}

public static double getRiemannSum(double s) {
    return riemannFuncForm(s);
}

Tester sur trois ou quatre valeurs montre que cela ne fonctionne pas. Si vous écrivez quelque chose de similaire à --

// Riemann's Functional Equation
public static double riemannFuncForm(double s) {
double currentVal = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s); //currVal*term
if( s == 1.0)
    return 0;
else if ( s == 0.0)
    return -0.5;
else //Otherwise just keep recursing
    return currentVal * nextVal(1-s);
}

public static double nextVal(double s)
{
    return (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
}

J'ai mal interprété comment faire cela à travers les mathématiques. Je devrai utiliser une approximation différente de la fonction zêta pour les valeurs inférieures à 2.

 0
Author: Axion004, 2015-06-13 19:46:03

Je pense que je dois utiliser une forme différente de la fonction zêta. Quand j'exécute tout le programme - - -

import java.util.Scanner;

public class Test4{

public static void main(String[] args) {
    RiemannZetaMain func = new RiemannZetaMain();
    double s = 0;
    double start, stop, totalTime;
    Scanner scan = new Scanner(System.in);
    System.out.print("Enter the value of s inside the Riemann Zeta Function: ");
    try {
            s = scan.nextDouble();
    } 
    catch (Exception e) {
        System.out.println("You must enter a positive integer greater than 1.");
    }
    start = System.currentTimeMillis();
    if(s >= 2)
        System.out.println("Value for the Zeta Function = " + getStandardSum(s));
    else
        System.out.println("Value for the Zeta Function = " + getRiemannSum(s));
    stop = System.currentTimeMillis();
    totalTime = (double) (stop-start) / 1000.0;
    System.out.println("Total time taken is " + totalTime + " seconds.");
}

// Standard form the the Zeta function.
public static double standardZeta(double s) {
    int n = 1;
    double currentSum = 0;
    double relativeError = 1;
    double error = 0.000001;
    double remainder;

    while (relativeError > error) {
        currentSum = Math.pow(n, -s) + currentSum;
        remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
        relativeError =  remainder / currentSum;
        n++;
    }
    System.out.println("The number of terms summed was " + n + ".");
    return currentSum;
}

public static double getStandardSum(double s){
    return standardZeta(s);
}

// Riemann's Functional Equation
public static double riemannFuncForm(double s, double threshold, double currSteps, int maxSteps) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
//double nextTerm = Math.pow(2, (1-s))*Math.pow(Math.PI, (1-s)-1)*(Math.sin((Math.PI*(1-s))/2))*gamma(1-(1-s));
//double error = Math.abs(term - nextTerm);

if(s == 1.0)
    return 0;
else if (s == 0.0)
    return -0.5;
else if (term < threshold) {//The recursion will stop once the term is less than the threshold
    System.out.println("The number of steps is " + currSteps);
    return term;
}
else if (currSteps == maxSteps) {//The recursion will stop if you meet the max steps
    System.out.println("The series did not converge.");
    return term;
}    
else //Otherwise just keep recursing
    return term*riemannFuncForm(1-s, threshold, ++currSteps, maxSteps);
}

public static double getRiemannSum(double s) {
    double threshold = 0.00001;
    double currSteps = 1;
    int maxSteps = 1000;
    return riemannFuncForm(s, threshold, currSteps, maxSteps);
}

// Gamma Function - Lanczos approximation
public static double gamma(double s){
                double[] p = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
                                  771.32342877765313, -176.61502916214059, 12.507343278686905,
                                  -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
                int g = 7;
                if(s < 0.5) return Math.PI / (Math.sin(Math.PI * s)*gamma(1-s));

                s -= 1;
                double a = p[0];
                double t = s+g+0.5;
                for(int i = 1; i < p.length; i++){
                        a += p[i]/(s+i);
                }

                return Math.sqrt(2*Math.PI)*Math.pow(t, s+0.5)*Math.exp(-t)*a;
        }

//Binomial Co-efficient
public static double binomial(int n, int k)
{
    if (k>n-k)
        k=n-k;

    long b=1;
    for (int i=1, m=n; i<=k; i++, m--)
        b=b*m/i;
    return b;
}

}

Je remarque que brancher zeta (-1) renvoie -

Enter the value of s inside the Riemann Zeta Function: -1
The number of steps is 1.0
Value for the Zeta Function = -0.0506605918211689
Total time taken is 0.0 seconds.

Je savais que cette valeur était -1/12. J'ai vérifié d'autres valeurs avec wolfram alpha et observé que {

double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);

Renvoie la valeur correcte. C'est juste que je multiplie cette valeur à chaque fois par zêta(1-s). Dans le cas de Zeta(1/2), cela multipliera toujours le résultat par 0.99999999.

Enter the value of s inside the Riemann Zeta Function: 0.5
The series did not converge.
Value for the Zeta Function = 0.999999999999889
Total time taken is 0.006 seconds.

Je vais voir si je peux remplacer la partie pour --

    else if (term < threshold) {//The recursion will stop once the term is less than the threshold
    System.out.println("The number of steps is " + currSteps);
    return term;
}

Cette différence est l'erreur entre deux termes dans la sommation. Je ne pense peut-être pas à cela correctement, il est 1h16 du matin en ce moment. Laisse - moi voir si je peux penser mieux demain ....

 -1
Author: Axion004, 2015-06-13 05:18:56