You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java实现Mandelbrot集缩放模糊及计算停滞问题求助

Mandelbrot集程序问题排查

问题1:基于double实现的异常表现

  • 缩放约14次后图像出现模糊,调整MAX_ITER(从100到100000)无法改善该现象
  • 前两次缩放需要耗时数秒,后续缩放则瞬间完成

问题2:改用BigDecimal后的运行异常

  • 替换为BigDecimal后,computeIterations方法运行速度骤降甚至直接停滞
  • 循环会在x值为256-258左右停止(修改窗口宽高后,停止位置约为宽度的5/8处)

相关代码

import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.math.BigDecimal;

public class test extends JFrame {
  
  static final int WIDTH  = 400;
  static final int HEIGHT = WIDTH;
  
  Canvas canvas;
  BufferedImage fractalImage;
  
  static final int MAX_ITER = 10000;
  static final BigDecimal DEFAULT_TOP_LEFT_X = new BigDecimal(-2.0);
  static final BigDecimal DEFAULT_TOP_LEFT_Y = new BigDecimal(1.4); 
  static final double DEFAULT_ZOOM       = Math.round((double) (WIDTH/3));
  final int numThreads = 10;
  
  double zoomFactor = DEFAULT_ZOOM;
  BigDecimal topLeftX   = DEFAULT_TOP_LEFT_X;
  BigDecimal topLeftY   = DEFAULT_TOP_LEFT_Y;
  
  BigDecimal z_r = new BigDecimal(0.0);
  BigDecimal z_i = new BigDecimal(0.0);

// -------------------------------------------------------------------
  public test() {
    setInitialGUIProperties();
    addCanvas();
    canvas.addKeyStrokeEvents();
    updateFractal();
    this.setVisible(true);
  }
  
// -------------------------------------------------------------------

  public static void main(String[] args) {
    new test();
  }
  
// -------------------------------------------------------------------

  private void addCanvas() {

    canvas = new Canvas();
    fractalImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
    canvas.setVisible(true);
    this.add(canvas, BorderLayout.CENTER);

  } // addCanvas

// -------------------------------------------------------------------
    
    private void setInitialGUIProperties() {
      
      this.setTitle("Fractal Explorer");
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.setSize(WIDTH, HEIGHT);
      this.setResizable(false);
      this.setLocationRelativeTo(null);
    } // setInitialGUIProperties

// -------------------------------------------------------------------
  private BigDecimal getXPos(double x) {
    return topLeftX.add(new BigDecimal(x/zoomFactor));
  } // getXPos
// -------------------------------------------------------------------
  private BigDecimal getYPos(double y) {
    return topLeftY.subtract(new BigDecimal(y/zoomFactor));
  } // getYPos
// -------------------------------------------------------------------
  
  /**
   * Aktualisiert das Fraktal, indem die Anzahl der Iterationen für jeden Punkt im Fraktal berechnet wird und die Farbe basierend darauf geändert wird.
   **/
  
  public void updateFractal() {
    Thread[] threads = new Thread[numThreads];
    int rowsPerThread = HEIGHT / numThreads;
    
    // Construct each thread
    for (int i=0; i<numThreads; i++) {
      threads[i] = new Thread(new FractalThread(i * rowsPerThread, (i+1) * rowsPerThread));
    }
    
    // Starte jeden thread
    for (int i=0; i<numThreads; i++) {
      threads[i].start();
    }
    
    // Warten bis alle threads fertig sind
    for (int i=0; i<numThreads; i++) {
      try {
        threads[i].join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    
    canvas.repaint();
    
  } // updateFractal
// -------------------------------------------------------------------  
  //Gibt basierend auf der Iterationsanzahl eine trennungsfarbe zurück eines gegebenen Punktes im Fraktal
  private class FractalThread implements Runnable {
    
    int startY;
    int endY;
    
    public FractalThread(int startY, int endY) {
      this.startY = startY;
      this.endY = endY;
    }
    
    public void run() {
      BigDecimal c_r;
      BigDecimal c_i;
      for (int x = 0; x < WIDTH; x++ ) {
        for (int y = startY; y < endY; y++ ) {
          
          c_r = getXPos(x);
          c_i = getYPos(y);
          int iterCount = computeIterations(c_r, c_i);
                         
          int pixelColor = makeColor(iterCount);   
          fractalImage.setRGB(x, y, pixelColor);
        }
        System.out.println(x);
      }
      
    } // run
                           
  } // FractalThread
  private int makeColor( int iterCount ) {
    
    int color = 0b011011100001100101101000; 
    int mask  = 0b000000000000010101110111; 
    int shiftMag = iterCount / 13;
    
    if (iterCount == MAX_ITER) 
      return Color.BLACK.getRGB();
    
    return color | (mask << shiftMag);
    
  } // makeColor

// -------------------------------------------------------------------

  private int computeIterations(BigDecimal c_r, BigDecimal c_i) {
    BigDecimal z_r = new BigDecimal(0.0);
    BigDecimal z_i = new BigDecimal(0.0);
    BigDecimal z_r_tmp = z_r;
    BigDecimal dummy2 = new BigDecimal(2.0);
    int iterCount = 0;
    while ( z_r.doubleValue()*z_r.doubleValue() + z_i.doubleValue()*z_i.doubleValue() <= 4.0 ) { 
      z_r_tmp = z_r;
      z_r = z_r.multiply(z_r).subtract(z_i.multiply(z_r)).add(c_r);
      z_i = z_i.multiply(dummy2).multiply(z_i).multiply(z_r_tmp).add(c_i);
      
      if (iterCount >= MAX_ITER) return MAX_ITER;
      iterCount++;
    }
    
    return iterCount;
    
  } // computeIterations
// -------------------------------------------------------------------
  private void moveUp() {
    double curHeight = HEIGHT / zoomFactor;
    topLeftY = topLeftY.add(new BigDecimal(curHeight / 6));
    updateFractal();
  } // moveUp
// -------------------------------------------------------------------
  private void moveDown() {
    double curHeight = HEIGHT / zoomFactor;
    topLeftY = topLeftY.subtract(new BigDecimal(curHeight / 6));
    updateFractal();
  } // moveDown
// -------------------------------------------------------------------
  private void moveLeft() {
    double curWidth = WIDTH / zoomFactor;
    topLeftX = topLeftX.subtract(new BigDecimal(curWidth / 6));
    updateFractal();
  } // moveLeft
// -------------------------------------------------------------------
  private void moveRight() {
    double curWidth = WIDTH / zoomFactor;
    topLeftX = topLeftX.add(new BigDecimal(curWidth / 6));
    updateFractal();
  } // moveRight
// -------------------------------------------------------------------    

  private void adjustZoom( double newX, double newY, double newZoomFactor ) {
    
    topLeftX = topLeftX.add(new BigDecimal(newX/zoomFactor));
    topLeftY = topLeftY.subtract(new BigDecimal(newX/zoomFactor));
    zoomFactor = newZoomFactor;
    
    topLeftX = topLeftX.subtract(new BigDecimal(( WIDTH/2) / zoomFactor));
    topLeftY = topLeftY.add(new BigDecimal( (HEIGHT/2) / zoomFactor));
    updateFractal();
    
  } // adjustZoom

// -------------------------------------------------------------------  
  
  private class Canvas extends JPanel implements MouseListener {
    
    public Canvas() {
      addMouseListener(this);
    } 
    
    @Override public Dimension getPreferredSize() {
      return new Dimension(WIDTH, HEIGHT);
    } // getPreferredSize
    
    @Override public void paintComponent(Graphics drawingObj) {
      drawingObj.drawImage( fractalImage, 0, 0, null );
    } // paintComponent
    
    @Override public void mousePressed(MouseEvent mouse) {
      
      double x = (double) mouse.getX();
      double y = (double) mouse.getY();
      
      switch( mouse.getButton() ) {
        
        //Links
        case MouseEvent.BUTTON1:
          adjustZoom( x, y, zoomFactor*10 );
          break;

       // Rechts
        case MouseEvent.BUTTON3:
          adjustZoom( x, y, zoomFactor/2 );
          break; 
      }
    } // mousePressed
    
    public void addKeyStrokeEvents() {
      
      KeyStroke wKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, 0 );
      KeyStroke aKey = KeyStroke.getKeyStroke(KeyEvent.VK_A, 0 );
      KeyStroke sKey = KeyStroke.getKeyStroke(KeyEvent.VK_S, 0 );
      KeyStroke dKey = KeyStroke.getKeyStroke(KeyEvent.VK_D, 0 );
      
      Action wPressed = new AbstractAction() {
        @Override public void actionPerformed(ActionEvent e) {
          moveUp();
        }
      };
      
      Action aPressed = new AbstractAction() {
        @Override public void actionPerformed(ActionEvent e) {
          moveLeft();
        }
      };
      
      Action sPressed = new AbstractAction() {
        @Override public void actionPerformed(ActionEvent e) {
          moveDown();
        }
      };
      
      Action dPressed = new AbstractAction() {
        @Override public void actionPerformed(ActionEvent e) {
          moveRight();
        }
      };  
      
      this.getInputMap().put( wKey, "w_key" );
      this.getInputMap().put( aKey, "a_key" );
      this.getInputMap().put( sKey, "s_key" );
      this.getInputMap().put( dKey, "d_key" );
      
      this.getActionMap().put( "w_key", wPressed );
      this.getActionMap().put( "a_key", aPressed );
      this.getActionMap().put( "s_key", sPressed );
      this.getActionMap().put( "d_key", dPressed );
      
    } // addKeyStrokeEvents
    
    @Override public void mouseReleased(MouseEvent mouse){ }
    @Override public void mouseClicked(MouseEvent mouse) { }
    @Override public void mouseEntered(MouseEvent mouse) { }
    @Override public void mouseExited (MouseEvent mouse) { }
    
  } // Canvas
  
} // FractalExplorer

内容的提问来源于stack exchange,提问作者JoeSwansonJunior999

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:20:35