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
相关产品推荐
相关产品推荐

