首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java中的Riemann Zeta函数--函数形式的无限递归

Java中的Riemann Zeta函数--函数形式的无限递归
EN

Stack Overflow用户
提问于 2015-06-12 04:36:54
回答 3查看 2.4K关注 0票数 7

注:2015年6月17日更新。当然这是可能的。请参阅下面的解决方案。

即使有人复制和粘贴这些代码,您仍然需要进行大量的清理工作。还请注意,从Re(s) =0到Re(s) =1:,在关键条中会有问题。但这是个好的开始。

代码语言:javascript
复制
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);
}

}

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-13 05:18:56

我想我需要用另一种形式的zeta函数。当我运行整个程序时--

代码语言:javascript
复制
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;
}

}

我注意到插入zeta(-1)会返回-

代码语言:javascript
复制
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.

我知道这个值是-1/12。我用wolfram alpha检查了其他一些值,并观察到--

代码语言:javascript
复制
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);

返回正确的值。我只是每次都把这个值乘以zeta(1-s)。在Zeta(1/2)的情况下,这总是将结果乘以0.99999999。

代码语言:javascript
复制
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.

我要看看能不能把这个角色替换成--

代码语言:javascript
复制
    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;
}

这种差异是求和中两个术语之间的误差。我可能没有正确地考虑这个问题,现在是凌晨1点16分。让我看看明天我能不能想得更好..。

票数 -1
EN

Stack Overflow用户

发布于 2015-06-12 05:15:29

好的,我们已经知道,对于这个特殊的函数,由于它的这种形式实际上不是一个无穷级数,所以我们不能用递归来近似。然而,Riemann级数(1\(n^s) where n = 1 to infinity)的无限和可以用这种方法求解。

此外,该方法还可用于寻找任何无穷级数的和、积或极限.

如果您执行当前的代码,您将得到无限递归(例如,1-(1-s) = s1-s = t1-t = s,因此您只需在s的两个值之间无限地来回切换)。

下面我讲的是级数之和。现在看来,您正在计算该系列的产品。以下概念应适用于两者之一。

此外,Riemann函数是一个无穷级数函数。这意味着它只有一个极限,永远不会达到一个真正的和(在有限的时间),所以你不能得到一个确切的答案通过递归。

然而,如果你引入一个“阈值”因子,你可以得到一个近似,这是你喜欢的。随着每一项的增加,这一总和将增加/减少。一旦和稳定,您可以退出递归,并返回您的近似和。“稳定”是使用您的阈值系数定义的。一旦和的变化量低于这个阈值因子(您已经定义),您的和已经稳定。

阈值越小,近似越好,计算时间也越长。

(注意:只有当您的系列收敛时,如果它有可能不收敛,则可能需要在maxSteps变量中构建一个停止执行的方法,如果序列在递归的maxSteps步骤之后没有收敛到您的满意程度,则该方法才能工作。)

下面是一个示例实现,请注意,您必须使用thresholdmaxSteps来确定适当的值:

代码语言:javascript
复制
/* 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
EN

Stack Overflow用户

发布于 2015-06-13 19:46:03

这是不可能的

Riemann Zeta函数的函数形式是--

代码语言:javascript
复制
zeta(s) = 2^s pi^(-1+s) Gamma(1-s) sin((pi s)/2) zeta(1-s)

这不同于标准方程,即在所有k=1到k=无穷大的情况下,从1/k^s计算出无限和。我们可以把它写成类似--

代码语言:javascript
复制
// 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;
}

同样的逻辑不适用于函数方程(它不是一个直接和,而是一个数学关系)。这需要一种相当聪明的方法来设计一个程序来计算Zeta(s)的负值!

这个Java代码的字面解释是

代码语言:javascript
复制
// 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);
}

对三到四个值的测试表明,这是行不通的。如果你写的东西和.

代码语言:javascript
复制
// 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));
}

我误解了如何通过数学来做到这一点。对于小于2的值,我必须使用zeta函数的不同近似。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30795379

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档