首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >的程序似乎冻结了,尽管在较早的迭代中起作用

的程序似乎冻结了,尽管在较早的迭代中起作用
EN

Stack Overflow用户
提问于 2013-04-08 05:02:34
回答 1查看 196关注 0票数 0

我正在编写一个程序,通过寻找超稳定值,然后使用这些超稳定值的比率来计算常量,从而使用逻辑方程来计算费根鲍姆常数。

我几乎所有的值都使用BigDecimals,以便在计算常量时能够保持必要的精度。

我正在修改以下文件的第30-35页上的C++代码:http://webcache.googleusercontent.com/search?q=cache:xabTioRiF0IJ:home.simula.no/~logg/pub/reports/chaos_hw1.ps.gz+&cd=21&hl=en&ct=clnk&gl=us

我怀疑这个程序做了什么甚至对我的问题都很重要。我运行了这个程序,它似乎起作用了。我得到的前4个超稳定值和前2天的输出是预期的,但在显示这4行之后,程序似乎就停止了。我没有得到异常,但即使在等待了30分钟之后,也没有输出更多的计算。我不知道到底是什么原因造成的,因为每一行的计算时间应该大致相同,但显然并非如此。下面是我的输出:

代码语言:javascript
运行
复制
Feigenbaum constant calculation (using superstable points):
j       a           d
-----------------------------------------------------
1       2.0         N/A
2   3.23606797749979        N/A
4   3.4985616993277016  4.708943013540503
8   3.554640862768825   4.680770998010695

下面是我的代码:

代码语言:javascript
运行
复制
import java.math.*;


// If there is a stable cycle, the iterates of 1/2 converge to the cycle. 
// This was proved by Fatou and Julia. 
// (What's special about x = 1/2 is that it is the critical point, the point at which the logistic map's derivative is 0.)
// Source: http://classes.yale.edu/fractals/chaos/Cycles/LogisticCycles/CycleGeneology.html

public class Feigenbaum4
{
public static BigDecimal r[] = new BigDecimal[19];
public static int iter = 0;
public static int iter1 = 20; // Iterations for tolerance level 1
public static int iter2 = 10; // Iterations for tolerance level 2
public static BigDecimal tol1 = new BigDecimal("2E-31"); // Tolerance for convergence level 1
public static BigDecimal tol2 = new BigDecimal("2E-27"); // Tolerance for convergence level 2
public static BigDecimal step = new BigDecimal("0.01"); // step when looking for second superstable a
public static BigDecimal x0 = new BigDecimal(".5");
public static BigDecimal aZero = new BigDecimal("2.0");

public static void main(String [] args)
{
    System.out.println("Feigenbaum constant calculation (using superstable points):");
    System.out.println("j\t\ta\t\t\td");
    System.out.println("-----------------------------------------------------");

    int n = 20;
    if (FindFirstTwo())
    {
        FindRoots(n);
    }

}

public static BigDecimal F(BigDecimal a, BigDecimal x)
{
    BigDecimal temp = new BigDecimal("1");
    temp = temp.subtract(x);
    BigDecimal ans = (a.multiply(x.multiply(temp)));
    return ans;
}

public static BigDecimal Dfdx(BigDecimal a, BigDecimal x)
{
    BigDecimal ans = (a.subtract(x.multiply(a.multiply(new BigDecimal("2")))));
    return ans;
}

public static BigDecimal Dfda(BigDecimal x)
{
    BigDecimal temp = new BigDecimal("1");
    temp = temp.subtract(x);
    BigDecimal ans = (x.multiply(temp));
    return ans;
}

public static BigDecimal NewtonStep(BigDecimal a, BigDecimal x, int n)
{
    // This function returns the Newton step for finding the root, a,
    // of fn(x,a) - x = 0 for a fixed x = X

    BigDecimal fval = F(a, x);
    BigDecimal dval = Dfda(x);

    for (int i = 1; i < n; i++)
    {
        dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));
        fval = F(a, fval);
    }

    BigDecimal ans = fval.subtract(x);
    ans = ans.divide(dval, MathContext.DECIMAL64);
    ans = ans.negate();
    return ans;

}

public static BigDecimal Root(BigDecimal a0, int n)
{
    // Find the root a of fn(x,a) - x = 0 for fixed x = X
    // with Newton’s method. The initial guess is a0.
    //
    // On return iter is the number of iterations if
    // the root was found. If not, iter is -1.

    BigDecimal a = a0;
    BigDecimal a_old = a0;
    BigDecimal ans;

    // First iter1 iterations with a stricter criterion,
    // tol1 < tol2

    for (iter = 0; iter < iter1; iter++)
    {
        a = a.add(NewtonStep(a, x0, n));

        // check for convergence
        BigDecimal temp = a.subtract(a_old);
        temp = temp.divide(a_old, MathContext.DECIMAL64);
        ans = temp.abs();

        if (ans.compareTo(tol1) < 0)
        {
            return a;
        }

        a_old = a;
    }

    // If this doesn't work, do another iter2 iterations 
    // with the larger tolerance tol2
    for (; iter < (iter1 + iter2); iter++)
    {
        a = a.add(NewtonStep(a, x0, n));

        // check for convergence
        BigDecimal temp = a.subtract(a_old);
        temp = temp.divide(a_old, MathContext.DECIMAL64);
        ans = temp.abs();

        if (ans.compareTo(tol2) < 0)
        {
            return a;
        }

        a_old = a;
    }

    BigDecimal temp2 = a.subtract(a_old);
    temp2 = temp2.divide(a_old, MathContext.DECIMAL64);
    ans = temp2.abs();

    // If not out at this point, iterations did not converge
    System.out.println("Error: Iterations did not converge,");
    System.out.println("residual = " + ans.toString());

    iter = -1;

    return a;
}

public static boolean FindFirstTwo()
{
    BigDecimal guess = aZero;
    BigDecimal r0;
    BigDecimal r1;

    while (true)
    {
        r0 = Root(guess, 1);
        r1 = Root(guess, 2);

        if (iter == -1)
        {
            System.out.println("Error: Unable to find first two superstable orbits");
            return false;
        }

        BigDecimal temp = r0.add(tol1.multiply(new BigDecimal ("2")));
        if (temp.compareTo(r1) < 0)
        {
            System.out.println("1\t\t" + r0.doubleValue() + "\t\t\tN/A");
            System.out.println("2\t" + r1.doubleValue() + "\t\tN/A");

            r[0] = r0;
            r[1] = r1;

            return true;
        }

        guess = guess.add(step);

    }


}

public static void FindRoots(int n)
{
    int n1 = 4;
    BigDecimal delta = new BigDecimal(4.0);
    BigDecimal guess;

    for (int i = 2; i < n; i++)
    {
        // Computation

        BigDecimal temp = (r[i-1].subtract(r[i-2])).divide(delta, MathContext.DECIMAL64);
        guess = r[i-1].add(temp);
        r[i] = Root(guess, n1);
        BigDecimal temp2 = r[i-1].subtract(r[i-2]);
        BigDecimal temp3 = r[i].subtract(r[i-1]);
        delta = temp2.divide(temp3, MathContext.DECIMAL64);

        // Output

        System.out.println(n1 + "\t" + r[i].doubleValue() + "\t" + delta.doubleValue());

        // Step to next superstable orbit

        n1 = n1 * 2;
    }
}

}

编辑: Phil Steitz的答案基本上解决了我的问题。我查看了一些线程转储,在做了一些研究以尝试理解它们之后,并使用调试信息编译了我的程序,我能够发现主线程在这一行停滞:

代码语言:javascript
运行
复制
dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));

正如Phil Steit所说,通过使用

代码语言:javascript
运行
复制
MathContext.DECIMAL128

不仅在这一行中:

代码语言:javascript
运行
复制
 dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval));

而且在我的F、Dfda和Dfdx方法的乘法运算中,我也能够让我的代码正常工作。

我使用DECIMAL128,因为较小的精度使计算无效,因为我将它们与用于公差检查的如此低的数字进行比较。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-04-08 07:38:47

我认为这里发生的事情是,当n大于大约10时,你的NewtonStep方法会变得非常慢,因为你的multiply调用都没有通过提供MathContext来限制规模。如果未提供MathContext,则乘法的结果将得到被乘数的比例之和。使用上面的代码,对于很大的n,NewtonStep中for循环中的dvalfval的规模变得非常大,导致此方法和它所调用的方法的乘法非常慢。尝试在乘法激活中指定MathContext.DECIMAL64 (或其他东西),就像对除法一样。

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

https://stackoverflow.com/questions/15867773

复制
相关文章

相似问题

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