2013-04-07 65 views
0

我正在编写一个程序来计算Feigenbaum的常数使用物流方程通过查找superstable值,然后使用这些superstable值的比率来计算常数。程序似乎冻结了尽管在早期迭代功能

我使用BigDecimals几乎所有的值,这样我就可以在计算常量时保持必要的精确度。

我适应我的代码从C++代码上的以下文件的30-35页: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个d是预期的结果,但是在显示这4行后,程序似乎停止了。我没有例外,但是即使在等待30分钟后,也不会输出更多计算结果。我无法弄清楚究竟是什么造成的,因为每一行的计算时间应该大致相同,但它显然不是。这里是我的输出:

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 

这里是我的代码:

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; 
    } 
} 

}

编辑: 菲尔·施泰茨的回答根本上解决我的问题。我看了一些线程转储,并做了一些研究,试图了解他们,和编译我的程序与调试信息后,我能找到主线程在行拖延:

dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval)); 

菲尔Steit的说,通过这不仅行使用

MathContext.DECIMAL128 

:在方法楼DFDA和Dfdx

dval = Dfda(fval).add(Dfdx(a, fval).multiply(dval)); 

而且在我的乘法运算,我能得到我的代码正常工作。

我使用DECIMAL128,因为较小的精度使计算无法正常工作,因为我将它们与容差检查的这种低数字进行比较。

+1

您是否尝试过使用一些线程转储来查看进程可能挂起的位置? – Leon 2013-04-07 21:09:58

+1

我会建议你使用调试器,看看你的代码在阻塞线程转储时正在做什么。没有人会通过所有这些代码寻找一个错误。 – 2013-04-07 21:10:36

+0

bmorris591,你会推荐什么调试器?我没有任何类型的调试器的经验。 – mps62 2013-04-07 21:18:08

回答

2

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